2010-04-28 22:17:47

by Jonathan Corbet

[permalink] [raw]
Subject: [RFC] Second OLPC Viafb series, v2

This is the second posting of the second series of viafb patches. What's
added here is a big refactoring of the driver to split its functions apart
and the addition of code for GPIO, interrupt, DMA, and camera management.

The following changes have been made since the first version:

- A couple of small fixes have been made to the first series. The
OLPC-specific tests for i2c access have been removed since they broke
the linux-next build, and we don't try to do i2c on ports which have not
traditionally been used that way. For that reason, I'm including that
initial series here; the whole set applies to 2.6.34-rc3.

- The build problems encountered by Florian (GPIOLIB and module stuff)
have been fixed. I have *not* made fb/i2c/gpio into separate modules at
this point, though that is the clear destination of this work. That's a
bit messy and I didn't want to complicate these patches further; I will
do it in the future.

- I merged in all of Florian's cleanup patches from a couple of weeks
ago. I've not looked at the new suspend/resume patches yet.

Note that the camera driver (the last in the series) is not yet ready for
submission; I add it here for completeness.

The full series of patches can be pulled from:

git://git.lwn.net/linux-2.6.git viafb-posted

Some of this stuff is disruptive, and I only have one machine to test it
all on, so I'd really appreciate it if folks with other types of hardware
could try them out.

Chris Ball (1):
viafb: Add 1200x900 DCON/LCD panel modes for OLPC XO-1.5

Florian Tobias Schandinat (7):
viafb: package often used basic io functions
viafb: unify modesetting functions
viafb: move some modesetting functions to a seperate file
viafb: replace inb/outb
viafb: improve misc register handling
viafb: fix proc entry removal
viafb: make procfs entries optional

Harald Welte (4):
viafb: Fix various resource leaks during module_init()
viafb: use proper pci config API
viafb: Determine type of 2D engine and store it in chip_info
viafb: rework the I2C support in the VIA framebuffer driver

Jonathan Corbet (17):
viafb: Unmap the frame buffer on initialization error
viafb: Retain GEMODE reserved bits
viafb: Unify duplicated set_bpp() code
viafb: complete support for VX800/VX855 accelerated framebuffer
viafb: Only establish i2c busses on ports that always had them
viafb: Move core stuff into via-core.c
viafb: Separate global and fb-specific data
viafb: add a driver for GPIO lines
viafb: Convert GPIO and i2c to the new indexed port ops
viafb: Turn GPIO and i2c into proper platform devices
via: Do not attempt I/O on inactive I2C adapters
viafb: Introduce viafb_find_i2c_adapter()
via: Rationalize vt1636 detection
viafb: Add a simple interrupt management infrastructure
viafb: Add a simple VX855 DMA engine driver
viafb: Reserve framebuffer memory for the upcoming camera driver
viafb: Add a driver for the video capture engine

Paul Fox (1):
suppress verbose debug messages: change printk() to DEBUG_MSG()

drivers/video/Kconfig | 27
drivers/video/via/Makefile | 7
drivers/video/via/accel.c | 137 ++-
drivers/video/via/accel.h | 40 +
drivers/video/via/chip.h | 8
drivers/video/via/dvi.c | 37
drivers/video/via/global.c | 2
drivers/video/via/global.h | 1
drivers/video/via/hw.c | 308 +------
drivers/video/via/hw.h | 21
drivers/video/via/ioctl.h | 2
drivers/video/via/lcd.c | 31
drivers/video/via/lcd.h | 2
drivers/video/via/share.h | 9
drivers/video/via/via-camera.c | 1399 ++++++++++++++++++++++++++++++++++++
drivers/video/via/via-camera.h | 93 ++
drivers/video/via/via-core.c | 652 ++++++++++++++++
drivers/video/via/via-core.h | 173 ++++
drivers/video/via/via-gpio.c | 287 +++++++
drivers/video/via/via-gpio.h | 14
drivers/video/via/via_i2c.c | 230 ++++-
drivers/video/via/via_i2c.h | 24
drivers/video/via/via_io.h | 67 +
drivers/video/via/via_modesetting.c | 126 +++
drivers/video/via/via_modesetting.h | 38
drivers/video/via/viafbdev.c | 179 ++--
drivers/video/via/viafbdev.h | 14
drivers/video/via/viamode.c | 14
drivers/video/via/vt1636.c | 34
drivers/video/via/vt1636.h | 2
include/media/v4l2-chip-ident.h | 4
31 files changed, 3416 insertions(+), 566 deletions(-)

Thanks,

jon


2010-04-28 22:18:32

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 23/30] 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.

Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/accel.c | 16 ++++++++++++++++
drivers/video/via/via-core.h | 10 ++++++++++
2 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c
index e777468..189aba4 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 3d03141..087c562 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__ */
--
1.7.0.1

2010-04-28 22:18:35

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 24/30] viafb: Add a driver for the video capture engine

This driver will capture streaming video using the viafb capture engine.
It is used on OLPC XO 1.5 systems, and, in its current form, will probably
not work on anything else.

Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/Kconfig | 11 +-
drivers/video/via/Makefile | 1 +
drivers/video/via/via-camera.c | 1399 +++++++++++++++++++++++++++++++++++++++
drivers/video/via/via-camera.h | 93 +++
drivers/video/via/via-core.c | 5 +-
include/media/v4l2-chip-ident.h | 4 +
6 files changed, 1511 insertions(+), 2 deletions(-)
create mode 100644 drivers/video/via/via-camera.c
create mode 100644 drivers/video/via/via-camera.h

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 22c1662..a969f76 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1516,12 +1516,21 @@ config FB_VIA
This is the frame buffer device driver for Graphics chips of VIA
UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/
CN700/VN800,CX700/VX700,P4M890) and Chrome9 Family (K8M890,CN896
- /P4M900,VX800)
+ /P4M900,VX800,VX855)
Say Y if you have a VIA UniChrome graphics board.

To compile this driver as a module, choose M here: the
module will be called viafb.

+config FB_VIA_CAMERA
+ tristate "VIAFB camera controller support"
+ depends on FB_VIA
+ select VIDEOBUF_DMA_SG
+ help
+ Driver support for the integrated camera controller in VIA
+ Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems
+ with ov7670 sensors.
+
config FB_NEOMAGIC
tristate "NeoMagic display support"
depends on FB && PCI
diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile
index 2751cb2..05401b6 100644
--- a/drivers/video/via/Makefile
+++ b/drivers/video/via/Makefile
@@ -3,6 +3,7 @@
#

obj-$(CONFIG_FB_VIA) += viafb.o
+obj-$(CONFIG_FB_VIA_CAMERA) += via-camera.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 \
diff --git a/drivers/video/via/via-camera.c b/drivers/video/via/via-camera.c
new file mode 100644
index 0000000..34f969f
--- /dev/null
+++ b/drivers/video/via/via-camera.c
@@ -0,0 +1,1399 @@
+/*
+ * Driver for the VIA Chrome integrated camera controller.
+ *
+ * Copyright 2009,2010 Jonathan Corbet <[email protected]>
+ * Distributable under the terms of the GNU General Public License, version 2
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/videobuf-dma-sg.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_qos_params.h>
+
+#include "global.h"
+#include "via-core.h"
+#include "via-gpio.h"
+#include "via_i2c.h"
+#include "via-camera.h"
+
+MODULE_AUTHOR("Jonathan Corbet <[email protected]>");
+MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver");
+MODULE_LICENSE("GPL");
+
+static int flip_image;
+module_param(flip_image, bool, 0444);
+MODULE_PARM_DESC(flip_image,
+ "If set, the sensor will be instructed to flip the image "
+ "vertically.");
+
+#ifdef CONFIG_OLPC_XO_1_5
+static int override_serial;
+module_param(override_serial, bool, 0444);
+MODULE_PARM_DESC(override_serial,
+ "The camera driver will normally refuse to load if "
+ "the XO 1.5 serial port is enabled. Set this option "
+ "to force the issue.");
+#endif
+
+/*
+ * Basic window sizes.
+ */
+#define VGA_WIDTH 640
+#define VGA_HEIGHT 480
+#define QCIF_WIDTH 176
+#define QCIF_HEIGHT 144
+
+/*
+ * The structure describing our camera.
+ */
+enum viacam_opstate { S_IDLE = 0, S_RUNNING = 1 };
+
+static struct via_camera {
+ struct v4l2_device v4l2_dev;
+ struct video_device vdev;
+ struct v4l2_subdev *sensor;
+ struct platform_device *platdev;
+ struct viafb_dev *viadev;
+ struct mutex lock;
+ enum viacam_opstate opstate;
+ unsigned long flags;
+ /*
+ * GPIO info for power/reset management
+ */
+ int power_gpio;
+ int reset_gpio;
+ /*
+ * I/O memory stuff.
+ */
+ void __iomem *mmio; /* Where the registers live */
+ void __iomem *fbmem; /* Frame buffer memory */
+ u32 fb_offset; /* Reserved memory offset (FB) */
+ /*
+ * Capture buffers and related. The controller supports
+ * up to three, so that's what we have here. These buffers
+ * live in frame buffer memory, so we don't call them "DMA".
+ */
+ unsigned int cb_offsets[3]; /* offsets into fb mem */
+ u8 *cb_addrs[3]; /* Kernel-space addresses */
+ int n_cap_bufs; /* How many are we using? */
+ int next_buf;
+ struct videobuf_queue vb_queue;
+ struct list_head buffer_queue; /* prot. by reg_lock */
+ u64 dma_mask; /* A bit of a hack */
+ /*
+ * User tracking.
+ */
+ int users;
+ struct file *owner;
+ /*
+ * Video format information. sensor_format is kept in a form
+ * that we can use to pass to the sensor. We always run the
+ * sensor in VGA resolution, though, and let the controller
+ * downscale things if need be. So we keep the "real*
+ * dimensions separately.
+ */
+ struct v4l2_pix_format sensor_format;
+ struct v4l2_pix_format user_format;
+} via_cam_info;
+
+/*
+ * Flag values, manipulated with bitops
+ */
+#define CF_BUF0_VALID 0 /* Buffers valid - first three */
+#define CF_BUF1_VALID 1
+#define CF_BUF2_VALID 2
+#define CF_DMA_ACTIVE 3 /* A frame is incoming */
+#define CF_CONFIG_NEEDED 4 /* Must configure hardware */
+
+/*
+ * Stats, probably to be taken out.
+ */
+static int hardirqs, threadirqs, frames;
+static int noframe, nobuf, overruns;
+
+/*
+ * Nasty ugly v4l2 boilerplate.
+ */
+#define sensor_call(cam, optype, func, args...) \
+ v4l2_subdev_call(cam->sensor, optype, func, ##args)
+
+/*
+ * Debugging and related.
+ */
+#define cam_err(cam, fmt, arg...) \
+ dev_err(&(cam)->platdev->dev, fmt, ##arg);
+#define cam_warn(cam, fmt, arg...) \
+ dev_warn(&(cam)->platdev->dev, fmt, ##arg);
+#define cam_dbg(cam, fmt, arg...) \
+ dev_dbg(&(cam)->platdev->dev, fmt, ##arg);
+
+
+/*--------------------------------------------------------------------------*/
+/*
+ * Sensor power/reset management. This piece is OLPC-specific for
+ * sure; other configurations will have things connected differently.
+ */
+static int via_sensor_power_setup(struct via_camera *cam)
+{
+ int ret;
+
+ cam->power_gpio = viafb_gpio_lookup("VGPIO3");
+ cam->reset_gpio = viafb_gpio_lookup("VGPIO2");
+ if (cam->power_gpio < 0 || cam->reset_gpio < 0) {
+ dev_err(&cam->platdev->dev, "Unable to find GPIO lines\n");
+ return -EINVAL;
+ }
+ ret = gpio_request(cam->power_gpio, "viafb-camera");
+ if (ret) {
+ dev_err(&cam->platdev->dev, "Unable to request power GPIO\n");
+ return ret;
+ }
+ ret = gpio_request(cam->reset_gpio, "viafb-camera");
+ if (ret) {
+ dev_err(&cam->platdev->dev, "Unable to request reset GPIO\n");
+ gpio_free(cam->power_gpio);
+ return ret;
+ }
+ gpio_direction_output(cam->power_gpio, 0);
+ gpio_direction_output(cam->reset_gpio, 0);
+ return 0;
+}
+
+/*
+ * Power up the sensor and perform the reset dance.
+ */
+static void via_sensor_power_up(struct via_camera *cam)
+{
+ gpio_set_value(cam->power_gpio, 1);
+ gpio_set_value(cam->reset_gpio, 0);
+ msleep(20); /* Probably excessive */
+ gpio_set_value(cam->reset_gpio, 1);
+ msleep(20);
+}
+
+static void via_sensor_power_down(struct via_camera *cam)
+{
+ gpio_set_value(cam->power_gpio, 0);
+ gpio_set_value(cam->reset_gpio, 0);
+}
+
+
+static void via_sensor_power_release(struct via_camera *cam)
+{
+ via_sensor_power_down(cam);
+ gpio_free(cam->power_gpio);
+ gpio_free(cam->reset_gpio);
+}
+
+/* --------------------------------------------------------------------------*/
+/* Sensor ops */
+
+/*
+ * Manage the ov7670 "flip" bit, which needs special help.
+ */
+static int viacam_set_flip(struct via_camera *cam)
+{
+ struct v4l2_control ctrl;
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_VFLIP;
+ ctrl.value = flip_image;
+ return sensor_call(cam, core, s_ctrl, &ctrl);
+}
+
+/*
+ * Configure the sensor. It's up to the caller to ensure
+ * that the camera is in the correct operating state.
+ */
+static int viacam_configure_sensor(struct via_camera *cam)
+{
+ struct v4l2_format fmt;
+ int ret;
+
+ fmt.fmt.pix = cam->sensor_format;
+ ret = sensor_call(cam, core, init, 0);
+ if (ret == 0)
+ ret = sensor_call(cam, video, s_fmt, &fmt);
+ /*
+ * OV7670 does weird things if flip is set *before* format...
+ */
+ if (ret == 0)
+ ret = viacam_set_flip(cam);
+ return ret;
+}
+
+
+
+/* --------------------------------------------------------------------------*/
+/*
+ * Some simple register accessors; they assume that the lock is held.
+ *
+ * Should we want to support the second capture engine, we could
+ * hide the register difference by adding 0x1000 to registers in the
+ * 0x300-350 range.
+ */
+static inline void viacam_write_reg(struct via_camera *cam,
+ int reg, int value)
+{
+ iowrite32(value, cam->mmio + reg);
+}
+
+static inline int viacam_read_reg(struct via_camera *cam, int reg)
+{
+ return ioread32(cam->mmio + reg);
+}
+
+static inline void viacam_write_reg_mask(struct via_camera *cam,
+ int reg, int value, int mask)
+{
+ int tmp = viacam_read_reg(cam, reg);
+
+ tmp = (tmp & ~mask) | (value & mask);
+ viacam_write_reg(cam, reg, tmp);
+}
+
+
+/* --------------------------------------------------------------------------*/
+/* Interrupt management and handling */
+
+static irqreturn_t viacam_quick_irq(int irq, void *data)
+{
+ struct via_camera *cam = data;
+ irqreturn_t ret = IRQ_NONE;
+ int icv, frame;
+
+ /*
+ * All we do here is to clear the interrupts and tell
+ * the handler thread to wake up.
+ */
+ hardirqs++;
+ spin_lock(&cam->viadev->reg_lock);
+ icv = viacam_read_reg(cam, VCR_INTCTRL);
+ if (icv & VCR_IC_EAV) {
+ icv |= VCR_IC_EAV|VCR_IC_EVBI|VCR_IC_FFULL;
+ viacam_write_reg(cam, VCR_INTCTRL, icv);
+ /*
+ * Figure out which frame is valid. The via sample
+ * driver decrements by one, leading to the assumption
+ * that the counter has already moved on when the
+ * interrupt hits.
+ */
+ frame = ((icv & VCR_IC_ACTBUF) >> 3) - 1;
+ if (frame < 0)
+ frame = cam->n_cap_bufs - 1;
+ if (test_and_set_bit(frame, &cam->flags))
+ overruns++;
+ ret = IRQ_WAKE_THREAD;
+ }
+ spin_unlock(&cam->viadev->reg_lock);
+ return ret;
+}
+
+static struct videobuf_buffer *viacam_next_buffer(struct via_camera *cam)
+{
+ unsigned long flags;
+ struct videobuf_buffer *buf = NULL;
+
+ spin_lock_irqsave(&cam->viadev->reg_lock, flags);
+ if (cam->opstate != S_RUNNING)
+ goto out;
+ if (list_empty(&cam->buffer_queue))
+ goto out;
+ buf = list_entry(cam->buffer_queue.next, struct videobuf_buffer, queue);
+ if (!waitqueue_active(&buf->done)) {/* Nobody waiting */
+ buf = NULL;
+ goto out;
+ }
+ list_del(&buf->queue);
+ buf->state = VIDEOBUF_ACTIVE;
+out:
+ spin_unlock_irqrestore(&cam->viadev->reg_lock, flags);
+ return buf;
+}
+
+/*
+ * The threaded IRQ handler.
+ */
+static irqreturn_t viacam_irq(int irq, void *data)
+{
+ int bufn;
+ struct videobuf_buffer *vb;
+ struct via_camera *cam = data;
+ struct videobuf_dmabuf *vdma;
+
+ threadirqs++;
+ /*
+ * If there is no place to put the data frame, don't bother
+ * with anything else.
+ */
+ vb = viacam_next_buffer(cam);
+ if (vb == NULL) {
+ nobuf++;
+ goto done;
+ }
+ /*
+ * Figure out which buffer will remain unmolested by
+ * the capture engine for the longest.
+ */
+ bufn = (viacam_read_reg(cam, VCR_INTCTRL) & VCR_IC_ACTBUF) >> 3;
+ bufn += 1;
+ if (bufn >= cam->n_cap_bufs)
+ bufn = 0;
+ clear_bit(bufn, &cam->flags); /* Unnecessary now */
+ /*
+ * Copy over the data and let any waiters know.
+ */
+ frames++;
+ vdma = videobuf_to_dma(vb);
+ viafb_dma_copy_out_sg(cam->cb_offsets[bufn], vdma->sglist, vdma->sglen);
+ vb->state = VIDEOBUF_DONE;
+ vb->size = cam->user_format.sizeimage;
+ wake_up(&vb->done);
+done:
+ return IRQ_HANDLED;
+}
+
+
+/*
+ * These functions must mess around with the general interrupt
+ * control register, which is relevant to much more than just the
+ * camera. Nothing else uses interrupts, though, as of this writing.
+ * Should that situation change, we'll have to improve support at
+ * the via-core level.
+ */
+static void viacam_int_enable(struct via_camera *cam)
+{
+ viacam_write_reg(cam, VCR_INTCTRL,
+ VCR_IC_INTEN|VCR_IC_EAV|VCR_IC_EVBI|VCR_IC_FFULL);
+ viafb_irq_enable(VDE_I_C0AVEN);
+}
+
+static void viacam_int_disable(struct via_camera *cam)
+{
+ viafb_irq_disable(VDE_I_C0AVEN);
+ viacam_write_reg(cam, VCR_INTCTRL, 0);
+}
+
+
+
+/* --------------------------------------------------------------------------*/
+/* Controller operations */
+
+/*
+ * Set up our capture buffers in framebuffer memory.
+ */
+static int viacam_ctlr_cbufs(struct via_camera *cam)
+{
+ int nbuf = cam->viadev->camera_fbmem_size/cam->sensor_format.sizeimage;
+ int i;
+ unsigned int offset;
+
+ /*
+ * See how many buffers we can work with.
+ */
+ if (nbuf >= 3) {
+ cam->n_cap_bufs = 3;
+ viacam_write_reg_mask(cam, VCR_CAPINTC, VCR_CI_3BUFS,
+ VCR_CI_3BUFS);
+ } else if (nbuf == 2) {
+ cam->n_cap_bufs = 2;
+ viacam_write_reg_mask(cam, VCR_CAPINTC, 0, VCR_CI_3BUFS);
+ } else {
+ cam_warn(cam, "Insufficient frame buffer memory\n");
+ return -ENOMEM;
+ }
+ /*
+ * Set them up.
+ */
+ offset = cam->fb_offset;
+ for (i = 0; i < cam->n_cap_bufs; i++) {
+ cam->cb_offsets[i] = offset;
+ cam->cb_addrs[i] = cam->fbmem + offset;
+ viacam_write_reg(cam, VCR_VBUF1 + i*4, offset & VCR_VBUF_MASK);
+ offset += cam->sensor_format.sizeimage;
+ }
+ return 0;
+}
+
+/*
+ * Set the scaling register for downscaling the image.
+ *
+ * This register works like this... Vertical scaling is enabled
+ * by bit 26; if that bit is set, downscaling is controlled by the
+ * value in bits 16:25. Those bits are divided by 1024 to get
+ * the scaling factor; setting just bit 25 thus cuts the height
+ * in half.
+ *
+ * Horizontal scaling works about the same, but it's enabled by
+ * bit 11, with bits 0:10 giving the numerator of a fraction
+ * (over 2048) for the scaling value.
+ *
+ * This function is naive in that, if the user departs from
+ * the 3x4 VGA scaling factor, the image will distort. We
+ * could work around that if it really seemed important.
+ */
+static void viacam_set_scale(struct via_camera *cam)
+{
+ unsigned int avscale;
+ int sf;
+
+ if (cam->user_format.width == VGA_WIDTH)
+ avscale = 0;
+ else {
+ sf = (cam->user_format.width*2048)/VGA_WIDTH;
+ avscale = VCR_AVS_HEN | sf;
+ }
+ if (cam->user_format.height < VGA_HEIGHT) {
+ sf = (1024*cam->user_format.height)/VGA_HEIGHT;
+ avscale |= VCR_AVS_VEN | (sf << 16);
+ }
+ viacam_write_reg(cam, VCR_AVSCALE, avscale);
+}
+
+
+/*
+ * Configure image-related information into the capture engine.
+ */
+static void viacam_ctlr_image(struct via_camera *cam)
+{
+ int cicreg;
+
+ /*
+ * Disable clock before messing with stuff - from the via
+ * sample driver.
+ */
+ viacam_write_reg(cam, VCR_CAPINTC, ~VCR_CI_ENABLE);
+ viacam_write_reg(cam, VCR_CAPINTC, ~(VCR_CI_ENABLE|VCR_CI_CLKEN));
+ /*
+ * Disable a bunch of stuff (from via driver)
+ */
+ viacam_write_reg(cam, VCR_HORRANGE, 0x06200120);
+ viacam_write_reg(cam, VCR_VERTRANGE, 0x01de0000);
+ viacam_set_scale(cam);
+ /*
+ * Image size info.
+ */
+ viacam_write_reg(cam, VCR_MAXDATA,
+ (cam->sensor_format.height << 16) |
+ (cam->sensor_format.bytesperline >> 3));
+ viacam_write_reg(cam, VCR_MAXVBI, 0);
+ viacam_write_reg(cam, VCR_VSTRIDE,
+ cam->user_format.bytesperline & VCR_VS_STRIDE);
+ /*
+ * Set up the capture interface control register,
+ * everything but the "go" bit.
+ *
+ * The FIFO threshold is a bit of a magic number. Example
+ * value was 8, but that messes with the DMA engine; 0 works
+ * better.
+ */
+ cicreg = VCR_CI_CLKEN |
+ 0x00000000 | /* FIFO threshold */
+ VCR_CI_FLDINV | /* OLPC-specific? */
+ VCR_CI_VREFINV | /* OLPC-specific? */
+ VCR_CI_DIBOTH | /* Capture both fields */
+ VCR_CI_CCIR601_8;
+ if (cam->n_cap_bufs == 3)
+ cicreg |= VCR_CI_3BUFS;
+ /*
+ * YUV formats need different byte swapping than RGB.
+ */
+ if (cam->user_format.pixelformat == V4L2_PIX_FMT_YUYV)
+ cicreg |= VCR_CI_YUYV;
+ else
+ cicreg |= VCR_CI_UYVY;
+ viacam_write_reg(cam, VCR_CAPINTC, cicreg);
+}
+
+
+static int viacam_config_controller(struct via_camera *cam)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->viadev->reg_lock, flags);
+ ret = viacam_ctlr_cbufs(cam);
+ if (!ret)
+ viacam_ctlr_image(cam);
+ spin_unlock_irqrestore(&cam->viadev->reg_lock, flags);
+ clear_bit(CF_CONFIG_NEEDED, &cam->flags);
+ return ret;
+}
+
+/*
+ * Make it start grabbing data.
+ */
+static void viacam_start_engine(struct via_camera *cam)
+{
+ int i;
+
+ spin_lock_irq(&cam->viadev->reg_lock);
+ cam->next_buf = 0;
+ for (i = 0; i < cam->n_cap_bufs; i++)
+ clear_bit(i, &cam->flags);
+ viacam_write_reg_mask(cam, VCR_CAPINTC, VCR_CI_ENABLE, VCR_CI_ENABLE);
+ viacam_int_enable(cam);
+ (void) viacam_read_reg(cam, VCR_CAPINTC); /* Force post */
+ cam->opstate = S_RUNNING;
+ spin_unlock_irq(&cam->viadev->reg_lock);
+}
+
+
+static void viacam_stop_engine(struct via_camera *cam)
+{
+ spin_lock_irq(&cam->viadev->reg_lock);
+ viacam_int_disable(cam);
+ viacam_write_reg_mask(cam, VCR_CAPINTC, 0, VCR_CI_ENABLE);
+ (void) viacam_read_reg(cam, VCR_CAPINTC); /* Force post */
+ cam->opstate = S_IDLE;
+ spin_unlock_irq(&cam->viadev->reg_lock);
+}
+
+
+/* --------------------------------------------------------------------------*/
+/* Videobuf callback ops */
+
+/*
+ * buffer_setup. The purpose of this one would appear to be to tell
+ * videobuf how big a single image is. It's also evidently up to us
+ * to put some sort of limit on the maximum number of buffers allowed.
+ */
+static int viacam_vb_buf_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned int *size)
+{
+ struct via_camera *cam = q->priv_data;
+
+ *size = cam->user_format.sizeimage;
+ if (*count == 0 || *count > 6) /* Arbitrary number */
+ *count = 6;
+ return 0;
+}
+
+/*
+ * Prepare a buffer.
+ */
+static int viacam_vb_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct via_camera *cam = q->priv_data;
+
+ vb->size = cam->user_format.sizeimage;
+ vb->width = cam->user_format.width; /* bytesperline???? */
+ vb->height = cam->user_format.height;
+ vb->field = field;
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ int ret = videobuf_iolock(q, vb, NULL);
+ if (ret)
+ return ret;
+ }
+ vb->state = VIDEOBUF_PREPARED;
+ return 0;
+}
+
+/*
+ * We've got a buffer to put data into.
+ *
+ * FIXME: check for a running engine and valid buffers?
+ */
+static void viacam_vb_buf_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct via_camera *cam = q->priv_data;
+
+ /*
+ * Note that videobuf holds the lock when it calls
+ * us, so we need not (indeed, cannot) take it here.
+ */
+ vb->state = VIDEOBUF_QUEUED;
+ list_add_tail(&vb->queue, &cam->buffer_queue);
+}
+
+/*
+ * Free a buffer. Not sure why videobuf can't do this by
+ * itself.
+ */
+static void viacam_vb_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ videobuf_dma_unmap(q, videobuf_to_dma(vb));
+ videobuf_dma_free(videobuf_to_dma(vb));
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static const struct videobuf_queue_ops viacam_vb_ops = {
+ .buf_setup = viacam_vb_buf_setup,
+ .buf_prepare = viacam_vb_buf_prepare,
+ .buf_queue = viacam_vb_buf_queue,
+ .buf_release = viacam_vb_buf_release,
+};
+
+/* --------------------------------------------------------------------------*/
+/* File operations */
+
+static int viacam_open(struct file *filp)
+{
+ struct via_camera *cam = video_drvdata(filp);
+
+ filp->private_data = cam;
+ /*
+ * Note the new user. If this is the first one, we'll also
+ * need to power up the sensor.
+ */
+ mutex_lock(&cam->lock);
+ if (cam->users == 0) {
+ int ret = viafb_request_dma();
+
+ if (ret) {
+ mutex_unlock(&cam->lock);
+ return ret;
+ }
+ via_sensor_power_up(cam);
+ set_bit(CF_CONFIG_NEEDED, &cam->flags);
+ /*
+ * Hook into videobuf. Evidently this cannot fail.
+ */
+ videobuf_queue_sg_init(&cam->vb_queue, &viacam_vb_ops,
+ &cam->platdev->dev, &cam->viadev->reg_lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), cam);
+ }
+ (cam->users)++;
+ mutex_unlock(&cam->lock);
+ overruns = noframe = nobuf = hardirqs = threadirqs = frames = 0;
+ return 0;
+}
+
+static int viacam_release(struct file *filp)
+{
+ struct via_camera *cam = video_drvdata(filp);
+
+ cam_err(cam, "Release: %d hard, %d thread, %d frames\n", hardirqs,
+ threadirqs, frames);
+ cam_err(cam, "No frame %d, no buf %d overruns %d\n", noframe, nobuf,
+ overruns);
+ mutex_lock(&cam->lock);
+ (cam->users)--;
+ /*
+ * If the "owner" is closing, shut down any ongoing
+ * operations.
+ */
+ if (filp == cam->owner) {
+ videobuf_stop(&cam->vb_queue);
+ if (cam->opstate != S_IDLE)
+ viacam_stop_engine(cam);
+ cam->owner = NULL;
+ }
+ /*
+ * Last one out needs to turn out the lights.
+ */
+ if (cam->users == 0) {
+ videobuf_mmap_free(&cam->vb_queue);
+ via_sensor_power_down(cam);
+ viafb_release_dma();
+ }
+ mutex_unlock(&cam->lock);
+ return 0;
+}
+
+/*
+ * Read a frame from the device.
+ */
+static ssize_t viacam_read(struct file *filp, char __user *buffer,
+ size_t len, loff_t *pos)
+{
+ struct via_camera *cam = video_drvdata(filp);
+ int ret;
+
+ mutex_lock(&cam->lock);
+ /*
+ * Enforce the V4l2 "only one owner gets to read data" rule.
+ */
+ if (cam->owner && cam->owner != filp) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+ cam->owner = filp;
+ /*
+ * Do we need to configure the hardware?
+ */
+ if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) {
+ ret = viacam_configure_sensor(cam);
+ if (!ret)
+ ret = viacam_config_controller(cam);
+ if (ret)
+ goto out_unlock;
+ }
+ /*
+ * Fire up the capture engine, then have videobuf do
+ * the heavy lifting. Someday it would be good to avoid
+ * stopping and restarting the engine each time.
+ */
+ INIT_LIST_HEAD(&cam->buffer_queue);
+ viacam_start_engine(cam);
+ ret = videobuf_read_stream(&cam->vb_queue, buffer, len, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ viacam_stop_engine(cam);
+ /* videobuf_stop() ?? */
+
+out_unlock:
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+
+static unsigned int viacam_poll(struct file *filp, struct poll_table_struct *pt)
+{
+ struct via_camera *cam = video_drvdata(filp);
+
+ return videobuf_poll_stream(filp, &cam->vb_queue, pt);
+}
+
+
+static int viacam_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct via_camera *cam = video_drvdata(filp);
+
+ return videobuf_mmap_mapper(&cam->vb_queue, vma);
+}
+
+
+
+static const struct v4l2_file_operations viacam_fops = {
+ .owner = THIS_MODULE,
+ .open = viacam_open,
+ .release = viacam_release,
+ .read = viacam_read,
+ .poll = viacam_poll,
+ .mmap = viacam_mmap,
+ .ioctl = video_ioctl2,
+};
+
+/*----------------------------------------------------------------------------*/
+/*
+ * The long list of v4l2 ioctl ops
+ */
+
+static int viacam_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *ident)
+{
+ struct via_camera *cam = priv;
+
+ ident->ident = V4L2_IDENT_NONE;
+ ident->revision = 0;
+ if (v4l2_chip_match_host(&ident->match)) {
+ ident->ident = V4L2_IDENT_VIA_VX855;
+ return 0;
+ }
+ return sensor_call(cam, core, g_chip_ident, ident);
+}
+
+/*
+ * Control ops are passed through to the sensor.
+ */
+static int viacam_queryctrl(struct file *filp, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, core, queryctrl, qc);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+
+static int viacam_g_ctrl(struct file *filp, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, core, g_ctrl, ctrl);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+
+static int viacam_s_ctrl(struct file *filp, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, core, s_ctrl, ctrl);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+/*
+ * Only one input.
+ */
+static int viacam_enum_input(struct file *filp, void *priv,
+ struct v4l2_input *input)
+{
+ if (input->index != 0)
+ return -EINVAL;
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ input->std = V4L2_STD_ALL; /* Not sure what should go here */
+ strcpy(input->name, "Camera");
+ return 0;
+}
+
+static int viacam_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int viacam_s_input(struct file *filp, void *priv, unsigned int i)
+{
+ if (i != 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id *std)
+{
+ return 0;
+}
+
+/*
+ * Video format stuff. Here is our default format until
+ * user space messes with things.
+ */
+static struct v4l2_pix_format viacam_def_pix_format = {
+ .width = VGA_WIDTH,
+ .height = VGA_HEIGHT,
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .field = V4L2_FIELD_NONE,
+ .bytesperline = VGA_WIDTH*2,
+ .sizeimage = VGA_WIDTH*VGA_HEIGHT*2,
+};
+
+static int viacam_enum_fmt_vid_cap(struct file *filp, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, video, enum_fmt, fmt);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+/*
+ * Figure out proper image dimensions, but always force the
+ * sensor to VGA.
+ */
+static void viacam_fmt_pre(struct v4l2_pix_format *userfmt,
+ struct v4l2_pix_format *sensorfmt)
+{
+ *sensorfmt = *userfmt;
+ if (userfmt->width < QCIF_WIDTH || userfmt->height < QCIF_HEIGHT) {
+ userfmt->width = QCIF_WIDTH;
+ userfmt->height = QCIF_HEIGHT;
+ }
+ if (userfmt->width > VGA_WIDTH || userfmt->height > VGA_HEIGHT) {
+ userfmt->width = VGA_WIDTH;
+ userfmt->height = VGA_HEIGHT;
+ }
+ sensorfmt->width = VGA_WIDTH;
+ sensorfmt->height = VGA_HEIGHT;
+}
+
+static void viacam_fmt_post(struct v4l2_pix_format *userfmt,
+ struct v4l2_pix_format *sensorfmt)
+{
+ userfmt->pixelformat = sensorfmt->pixelformat;
+ userfmt->field = sensorfmt->field;
+ userfmt->bytesperline = 2*userfmt->width;
+ userfmt->sizeimage = userfmt->bytesperline*userfmt->height;
+}
+
+static int viacam_try_fmt_vid_cap(struct file *filp, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct via_camera *cam = priv;
+ int ret;
+ struct v4l2_format sfmt;
+
+ viacam_fmt_pre(&fmt->fmt.pix, &sfmt.fmt.pix);
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, video, try_fmt, &sfmt);
+ mutex_unlock(&cam->lock);
+ viacam_fmt_post(&fmt->fmt.pix, &sfmt.fmt.pix);
+ return ret;
+}
+
+static int viacam_g_fmt_vid_cap(struct file *filp, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct via_camera *cam = priv;
+
+ fmt->fmt.pix = cam->user_format;
+ return 0;
+}
+
+static int viacam_s_fmt_vid_cap(struct file *filp, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct via_camera *cam = priv;
+ int ret;
+ struct v4l2_format sfmt;
+
+ /*
+ * Camera must be idle or we can't mess with the
+ * video setup.
+ */
+ if (cam->opstate != S_IDLE)
+ return -EBUSY;
+ /*
+ * Let the sensor code look over and tweak the
+ * requested formatting.
+ */
+ mutex_lock(&cam->lock);
+ viacam_fmt_pre(&fmt->fmt.pix, &sfmt.fmt.pix);
+ ret = sensor_call(cam, video, try_fmt, &sfmt);
+ if (ret)
+ goto out;
+ viacam_fmt_post(&fmt->fmt.pix, &sfmt.fmt.pix);
+ /*
+ * OK, let's commit to the new format.
+ */
+ cam->user_format = fmt->fmt.pix;
+ cam->sensor_format = sfmt.fmt.pix;
+ ret = viacam_configure_sensor(cam);
+ if (!ret)
+ ret = viacam_config_controller(cam);
+out:
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+static int viacam_querycap(struct file *filp, void *priv,
+ struct v4l2_capability *cap)
+{
+ strcpy(cap->driver, "via-camera");
+ strcpy(cap->card, "via-camera");
+ cap->version = 1;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ return 0;
+}
+
+/*
+ * Streaming operations - pure videobuf stuff.
+ */
+static int viacam_reqbufs(struct file *filp, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct via_camera *cam = priv;
+
+ return videobuf_reqbufs(&cam->vb_queue, rb);
+}
+
+static int viacam_querybuf(struct file *filp, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct via_camera *cam = priv;
+
+ return videobuf_querybuf(&cam->vb_queue, buf);
+}
+
+static int viacam_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf)
+{
+ struct via_camera *cam = priv;
+
+ return videobuf_qbuf(&cam->vb_queue, buf);
+}
+
+static int viacam_dqbuf(struct file *filp, void *priv, struct v4l2_buffer *buf)
+{
+ struct via_camera *cam = priv;
+
+ return videobuf_dqbuf(&cam->vb_queue, buf, filp->f_flags & O_NONBLOCK);
+}
+
+static int viacam_streamon(struct file *filp, void *priv, enum v4l2_buf_type t)
+{
+ struct via_camera *cam = priv;
+ int ret = 0;
+
+ if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (cam->opstate != S_IDLE)
+ return -EBUSY;
+ /*
+ * Enforce the V4l2 "only one owner gets to read data" rule.
+ */
+ if (cam->owner && cam->owner != filp)
+ return -EBUSY;
+ cam->owner = filp;
+ /*
+ * Configure things if need be.
+ */
+ if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) {
+ mutex_lock(&cam->lock);
+ ret = viacam_configure_sensor(cam);
+ if (!ret)
+ ret = viacam_config_controller(cam);
+ mutex_unlock(&cam->lock);
+ }
+ /*
+ * If the CPU goes into C3, the DMA transfer gets corrupted and
+ * users start filing unsightly bug reports. Put in a "latency"
+ * requirement which will keep the CPU out of the deeper sleep
+ * states.
+ */
+ pm_qos_add_requirement(PM_QOS_CPU_DMA_LATENCY, "viafb-dma", 50);
+ /*
+ * Fire things up.
+ */
+ if (!ret) {
+ INIT_LIST_HEAD(&cam->buffer_queue);
+ ret = videobuf_streamon(&cam->vb_queue);
+ if (!ret)
+ viacam_start_engine(cam);
+ }
+ return ret;
+}
+
+static int viacam_streamoff(struct file *filp, void *priv, enum v4l2_buf_type t)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY, "viafb-dma");
+ viacam_stop_engine(cam);
+ /*
+ * Videobuf will recycle all of the outstanding buffers, but
+ * we should be sure we don't retain any references to
+ * any of them.
+ */
+ ret = videobuf_streamoff(&cam->vb_queue);
+ INIT_LIST_HEAD(&cam->buffer_queue);
+ return ret;
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int viacam_vidiocgmbuf(struct file *filp, void *priv,
+ struct video_mbuf *mbuf)
+{
+ struct via_camera *cam = priv;
+
+ return videobuf_cgmbuf(&cam->vb_queue, mbuf, 6);
+}
+#endif
+
+/* G/S_PARM */
+
+static int viacam_g_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, video, g_parm, parm);
+ mutex_unlock(&cam->lock);
+ parm->parm.capture.readbuffers = cam->n_cap_bufs;
+ return ret;
+}
+
+static int viacam_s_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, video, s_parm, parm);
+ mutex_unlock(&cam->lock);
+ parm->parm.capture.readbuffers = cam->n_cap_bufs;
+ return ret;
+}
+
+static int viacam_enum_framesizes(struct file *filp, void *priv,
+ struct v4l2_frmsizeenum *sizes)
+{
+ if (sizes->index != 0)
+ return -EINVAL;
+ sizes->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ sizes->stepwise.min_width = QCIF_WIDTH;
+ sizes->stepwise.min_height = QCIF_HEIGHT;
+ sizes->stepwise.max_width = VGA_WIDTH;
+ sizes->stepwise.max_height = VGA_HEIGHT;
+ sizes->stepwise.step_width = sizes->stepwise.step_height = 1;
+ return 0;
+}
+
+static int viacam_enum_frameintervals(struct file *filp, void *priv,
+ struct v4l2_frmivalenum *interval)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, video, enum_frameintervals, interval);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+
+
+static const struct v4l2_ioctl_ops viacam_ioctl_ops = {
+ .vidioc_g_chip_ident = viacam_g_chip_ident,
+ .vidioc_queryctrl = viacam_queryctrl,
+ .vidioc_g_ctrl = viacam_g_ctrl,
+ .vidioc_s_ctrl = viacam_s_ctrl,
+ .vidioc_enum_input = viacam_enum_input,
+ .vidioc_g_input = viacam_g_input,
+ .vidioc_s_input = viacam_s_input,
+ .vidioc_s_std = viacam_s_std,
+ .vidioc_enum_fmt_vid_cap = viacam_enum_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = viacam_try_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = viacam_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = viacam_s_fmt_vid_cap,
+ .vidioc_querycap = viacam_querycap,
+ .vidioc_reqbufs = viacam_reqbufs,
+ .vidioc_querybuf = viacam_querybuf,
+ .vidioc_qbuf = viacam_qbuf,
+ .vidioc_dqbuf = viacam_dqbuf,
+ .vidioc_streamon = viacam_streamon,
+ .vidioc_streamoff = viacam_streamoff,
+ .vidioc_g_parm = viacam_g_parm,
+ .vidioc_s_parm = viacam_s_parm,
+ .vidioc_enum_framesizes = viacam_enum_framesizes,
+ .vidioc_enum_frameintervals = viacam_enum_frameintervals,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = viacam_vidiocgmbuf,
+#endif
+};
+
+/*----------------------------------------------------------------------------*/
+
+/*
+ * Power management.
+ */
+
+/*
+ * Setup stuff.
+ */
+
+static struct video_device viacam_v4l_template = {
+ .name = "via-camera",
+ .minor = -1,
+ .tvnorms = V4L2_STD_NTSC_M,
+ .current_norm = V4L2_STD_NTSC_M,
+ .fops = &viacam_fops,
+ .ioctl_ops = &viacam_ioctl_ops,
+ .release = video_device_release_empty, /* Check this */
+};
+
+
+static __devinit int viacam_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct i2c_adapter *sensor_adapter;
+ struct viafb_dev *viadev = pdev->dev.platform_data;
+
+ /*
+ * Note that there are actually two capture channels on
+ * the device. We only deal with one for now. That
+ * is encoded here; nothing else assumes it's dealing with
+ * a unique capture device.
+ */
+ struct via_camera *cam = &via_cam_info;
+
+ /*
+ * Ensure that frame buffer memory has been set aside for
+ * this purpose. As an arbitrary limit, refuse to work
+ * with less than two frames of VGA 16-bit data.
+ *
+ * If we ever support the second port, we'll need to set
+ * aside more memory.
+ */
+ if (viadev->camera_fbmem_size < (VGA_HEIGHT*VGA_WIDTH*4)) {
+ printk(KERN_ERR "viacam: insufficient FB memory reserved\n");
+ return -ENOMEM;
+ }
+ /*
+ * Basic structure initialization.
+ */
+ cam->platdev = pdev;
+ cam->viadev = viadev;
+ cam->users = 0;
+ cam->owner = NULL;
+ cam->opstate = S_IDLE;
+ cam->user_format = cam->sensor_format = viacam_def_pix_format;
+ mutex_init(&cam->lock);
+ INIT_LIST_HEAD(&cam->buffer_queue);
+ cam->mmio = viadev->engine_mmio;
+ cam->fbmem = viadev->fbmem;
+ cam->fb_offset = viadev->camera_fbmem_offset;
+ cam->flags = 1 << CF_CONFIG_NEEDED;
+ /*
+ * Tell V4L that we exist.
+ */
+ ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to register v4l2 device\n");
+ return ret;
+ }
+ /*
+ * Hackery to convince the system that we can do DMA.
+ */
+ cam->dma_mask = 0xffffffff;
+ pdev->dev.dma_mask = &cam->dma_mask;
+ dma_set_mask(&pdev->dev, 0xffffffff);
+ /*
+ * Fire up the capture port. The write to 0x78 looks purely
+ * OLPCish; any system will need to tweak 0x1e.
+ */
+ via_write_reg_mask(VIASR, 0x78, 0, 0x80);
+ via_write_reg_mask(VIASR, 0x1e, 0xc0, 0xc0);
+ /*
+ * Get the sensor powered up.
+ */
+ ret = via_sensor_power_setup(cam);
+ if (ret)
+ goto out_unregister;
+ via_sensor_power_up(cam);
+
+ /*
+ * See if we can't find it on the bus. The VIA_PORT_31 assumption
+ * is OLPC-specific. 0x42 assumption is ov7670-specific.
+ */
+ sensor_adapter = viafb_find_i2c_adapter(VIA_PORT_31);
+ cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, sensor_adapter,
+ "ov7670", "ov7670", 0x42 >> 1, NULL);
+ if (cam->sensor == NULL) {
+ dev_err(&pdev->dev, "Unable to find the sensor!\n");
+ ret = -ENODEV;
+ goto out_power_down;
+ }
+ /*
+ * Get the IRQ.
+ */
+ viacam_int_disable(cam);
+ ret = request_threaded_irq(viadev->pdev->irq, viacam_quick_irq,
+ viacam_irq, IRQF_SHARED, "via-camera", cam);
+ if (ret)
+ goto out_power_down;
+ /*
+ * Tell V4l2 that we exist.
+ */
+ cam->vdev = viacam_v4l_template;
+ cam->vdev.v4l2_dev = &cam->v4l2_dev;
+ ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret)
+ goto out_irq;
+ video_set_drvdata(&cam->vdev, cam);
+
+ /* Power the sensor down until somebody opens the device */
+ via_sensor_power_down(cam);
+ return 0;
+
+out_irq:
+ free_irq(viadev->pdev->irq, cam);
+out_power_down:
+ via_sensor_power_release(cam);
+out_unregister:
+ v4l2_device_unregister(&cam->v4l2_dev);
+ return ret;
+}
+
+static __devexit int viacam_remove(struct platform_device *pdev)
+{
+ struct via_camera *cam = &via_cam_info;
+ struct viafb_dev *viadev = pdev->dev.platform_data;
+
+ video_unregister_device(&cam->vdev);
+ v4l2_device_unregister(&cam->v4l2_dev);
+ free_irq(viadev->pdev->irq, cam);
+ via_sensor_power_release(cam);
+ return 0;
+}
+
+
+static struct platform_driver viacam_driver = {
+ .driver = {
+ .name = "viafb-camera",
+ },
+ .probe = viacam_probe,
+ .remove = viacam_remove,
+};
+
+
+#ifdef CONFIG_OLPC_XO_1_5
+/*
+ * The OLPC folks put the serial port on the same pin as
+ * the camera. They also get grumpy if we break the
+ * serial port and keep them from using it. So we have
+ * to check the serial enable bit and not step on it.
+ */
+#define VIACAM_SERIAL_DEVFN 0x88
+#define VIACAM_SERIAL_CREG 0x46
+#define VIACAM_SERIAL_BIT 0x40
+
+static __devinit int viacam_check_serial_port(void)
+{
+ struct pci_bus *pbus = pci_find_bus(0, 0);
+ u8 cbyte;
+
+ pci_bus_read_config_byte(pbus, VIACAM_SERIAL_DEVFN,
+ VIACAM_SERIAL_CREG, &cbyte);
+ if ((cbyte & VIACAM_SERIAL_BIT) == 0)
+ return 0; /* Not enabled */
+ if (override_serial == 0) {
+ printk(KERN_NOTICE "Via camera: serial port is enabled, " \
+ "refusing to load.\n");
+ printk(KERN_NOTICE "Specify override_serial=1 to force " \
+ "module loading.\n");
+ return -EBUSY;
+ }
+ printk(KERN_NOTICE "Via camera: overriding serial port\n");
+ pci_bus_write_config_byte(pbus, VIACAM_SERIAL_DEVFN,
+ VIACAM_SERIAL_CREG, cbyte & ~VIACAM_SERIAL_BIT);
+ return 0;
+}
+#endif
+
+
+
+
+static int viacam_init(void)
+{
+#ifdef CONFIG_OLPC_XO_1_5
+ if (viacam_check_serial_port())
+ return -EBUSY;
+#endif
+ return platform_driver_register(&viacam_driver);
+}
+module_init(viacam_init);
+
+static void viacam_exit(void)
+{
+ platform_driver_unregister(&viacam_driver);
+}
+module_exit(viacam_exit);
diff --git a/drivers/video/via/via-camera.h b/drivers/video/via/via-camera.h
new file mode 100644
index 0000000..b12a4b3
--- /dev/null
+++ b/drivers/video/via/via-camera.h
@@ -0,0 +1,93 @@
+/*
+ * VIA Camera register definitions.
+ */
+#define VCR_INTCTRL 0x300 /* Capture interrupt control */
+#define VCR_IC_EAV 0x0001 /* End of active video status */
+#define VCR_IC_EVBI 0x0002 /* End of VBI status */
+#define VCR_IC_FBOTFLD 0x0004 /* "flipping" Bottom field is active */
+#define VCR_IC_ACTBUF 0x0018 /* Active video buffer */
+#define VCR_IC_VSYNC 0x0020 /* 0 = VB, 1 = active video */
+#define VCR_IC_BOTFLD 0x0040 /* Bottom field is active */
+#define VCR_IC_FFULL 0x0080 /* FIFO full */
+#define VCR_IC_INTEN 0x0100 /* End of active video int. enable */
+#define VCR_IC_VBIINT 0x0200 /* End of VBI int enable */
+#define VCR_IC_VBIBUF 0x0400 /* Current VBI buffer */
+
+#define VCR_TSC 0x308 /* Transport stream control */
+#define VCR_TSC_ENABLE 0x000001 /* Transport stream input enable */
+#define VCR_TSC_DROPERR 0x000002 /* Drop error packets */
+#define VCR_TSC_METHOD 0x00000c /* DMA method (non-functional) */
+#define VCR_TSC_COUNT 0x07fff0 /* KByte or packet count */
+#define VCR_TSC_CBMODE 0x080000 /* Change buffer by byte count */
+#define VCR_TSC_PSSIG 0x100000 /* Packet starting signal disable */
+#define VCR_TSC_BE 0x200000 /* MSB first (serial mode) */
+#define VCR_TSC_SERIAL 0x400000 /* Serial input (0 = parallel) */
+
+#define VCR_CAPINTC 0x310 /* Capture interface control */
+#define VCR_CI_ENABLE 0x00000001 /* Capture enable */
+#define VCR_CI_BSS 0x00000002 /* WTF "bit stream selection" */
+#define VCR_CI_3BUFS 0x00000004 /* 1 = 3 buffers, 0 = 2 buffers */
+#define VCR_CI_VIPEN 0x00000008 /* VIP enable */
+#define VCR_CI_CCIR601_8 0 /* CCIR601 input stream, 8 bit */
+#define VCR_CI_CCIR656_8 0x00000010 /* ... CCIR656, 8 bit */
+#define VCR_CI_CCIR601_16 0x00000020 /* ... CCIR601, 16 bit */
+#define VCR_CI_CCIR656_16 0x00000030 /* ... CCIR656, 16 bit */
+#define VCR_CI_HDMODE 0x00000040 /* CCIR656-16 hdr decode mode; 1=16b */
+#define VCR_CI_BSWAP 0x00000080 /* Swap bytes (16-bit) */
+#define VCR_CI_YUYV 0 /* Byte order 0123 */
+#define VCR_CI_UYVY 0x00000100 /* Byte order 1032 */
+#define VCR_CI_YVYU 0x00000200 /* Byte order 0321 */
+#define VCR_CI_VYUY 0x00000300 /* Byte order 3012 */
+#define VCR_CI_VIPTYPE 0x00000400 /* VIP type */
+#define VCR_CI_IFSEN 0x00000800 /* Input field signal enable */
+#define VCR_CI_DIODD 0 /* De-interlace odd, 30fps */
+#define VCR_CI_DIEVEN 0x00001000 /* ...even field, 30fps */
+#define VCR_CI_DIBOTH 0x00002000 /* ...both fields, 60fps */
+#define VCR_CI_DIBOTH30 0x00003000 /* ...both fields, 30fps interlace */
+#define VCR_CI_CONVTYPE 0x00004000 /* 4:2:2 to 4:4:4; 1 = interpolate */
+#define VCR_CI_CFC 0x00008000 /* Capture flipping control */
+#define VCR_CI_FILTER 0x00070000 /* Horiz filter mode select
+ 000 = none
+ 001 = 2 tap
+ 010 = 3 tap
+ 011 = 4 tap
+ 100 = 5 tap */
+#define VCR_CI_CLKINV 0x00080000 /* Input CLK inverted */
+#define VCR_CI_VREFINV 0x00100000 /* VREF inverted */
+#define VCR_CI_HREFINV 0x00200000 /* HREF inverted */
+#define VCR_CI_FLDINV 0x00400000 /* Field inverted */
+#define VCR_CI_CLKPIN 0x00800000 /* Capture clock pin */
+#define VCR_CI_THRESH 0x0f000000 /* Capture fifo threshold */
+#define VCR_CI_HRLE 0x10000000 /* Positive edge of HREF */
+#define VCR_CI_VRLE 0x20000000 /* Positive edge of VREF */
+#define VCR_CI_OFLDINV 0x40000000 /* Field output inverted */
+#define VCR_CI_CLKEN 0x80000000 /* Capture clock enable */
+
+#define VCR_HORRANGE 0x314 /* Active video horizontal range */
+#define VCR_VERTRANGE 0x318 /* Active video vertical range */
+#define VCR_AVSCALE 0x31c /* Active video scaling control */
+#define VCR_AVS_HEN 0x00000800 /* Horizontal scale enable */
+#define VCR_AVS_VEN 0x04000000 /* Vertical enable */
+#define VCR_VBIHOR 0x320 /* VBI Data horizontal range */
+#define VCR_VBIVERT 0x324 /* VBI data vertical range */
+#define VCR_VBIBUF1 0x328 /* First VBI buffer */
+#define VCR_VBISTRIDE 0x32c /* VBI stride */
+#define VCR_ANCDATACNT 0x330 /* Ancillary data count setting */
+#define VCR_MAXDATA 0x334 /* Active data count of active video */
+#define VCR_MAXVBI 0x338 /* Maximum data count of VBI */
+#define VCR_CAPDATA 0x33c /* Capture data count */
+#define VCR_VBUF1 0x340 /* First video buffer */
+#define VCR_VBUF2 0x344 /* Second video buffer */
+#define VCR_VBUF3 0x348 /* Third video buffer */
+#define VCR_VBUF_MASK 0x1ffffff0 /* Bits 28:4 */
+#define VCR_VBIBUF2 0x34c /* Second VBI buffer */
+#define VCR_VSTRIDE 0x350 /* Stride of video + coring control */
+#define VCR_VS_STRIDE_SHIFT 4
+#define VCR_VS_STRIDE 0x00001ff0 /* Stride (8-byte units) */
+#define VCR_VS_CCD 0x007f0000 /* Coring compare data */
+#define VCR_VS_COREEN 0x00800000 /* Coring enable */
+#define VCR_TS0ERR 0x354 /* TS buffer 0 error indicator */
+#define VCR_TS1ERR 0x358 /* TS buffer 0 error indicator */
+#define VCR_TS2ERR 0x35c /* TS buffer 0 error indicator */
+
+/* Add 0x1000 for the second capture engine registers */
diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
index 83a8d34..58256d0 100644
--- a/drivers/video/via/via-core.c
+++ b/drivers/video/via/via-core.c
@@ -493,7 +493,10 @@ static struct viafb_subdev_info {
},
{
.name = "viafb-i2c",
- }
+ },
+ {
+ .name = "viafb-camera",
+ },
};
#define N_SUBDEVS ARRAY_SIZE(viafb_subdevs)

diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
index 56abf21..627a051 100644
--- a/include/media/v4l2-chip-ident.h
+++ b/include/media/v4l2-chip-ident.h
@@ -107,6 +107,10 @@ enum {
V4L2_IDENT_VPX3216B = 3216,
V4L2_IDENT_VPX3220A = 3220,

+ /* VX855: just ident 3409. Other via devs could use 3314, 3324,
+ 3327, 3336, 3364, and 3353 */
+ V4L2_IDENT_VIA_VX855 = 3409,
+
/* module tvp5150 */
V4L2_IDENT_TVP5150 = 5150,

--
1.7.0.1

2010-04-28 22:18:51

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 30/30] viafb: make procfs entries optional

From: Florian Tobias Schandinat <[email protected]>

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 <[email protected]>
---
drivers/video/Kconfig | 14 ++++++++++++++
drivers/video/via/viafbdev.c | 8 ++++++++
2 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index a969f76..f263564 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1531,6 +1531,20 @@ config FB_VIA_CAMERA
Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems
with ov7670 sensors.

+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 51e9106..3d03318 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);
--
1.7.0.1

2010-04-28 22:19:07

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 29/30] viafb: fix proc entry removal

From: Florian Tobias Schandinat <[email protected]>

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 <[email protected]>
---
drivers/video/via/viafbdev.c | 13 +++++++------
1 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index e94f913..51e9106 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
--
1.7.0.1

2010-04-28 22:19:11

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 28/30] viafb: improve misc register handling

From: Florian Tobias Schandinat <[email protected]>

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 <[email protected]>
---
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(-)

diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index b2bb24e..e356fe8 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 f974c73..861b414 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 e1c1093..a3d2aca 100644
--- a/drivers/video/via/via_io.h
+++ b/drivers/video/via/via_io.h
@@ -29,6 +29,9 @@
#include <linux/types.h>
#include <linux/io.h>

+#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__ */
--
1.7.0.1

2010-04-28 22:19:44

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 25/30] viafb: unify modesetting functions

From: Florian Tobias Schandinat <[email protected]>

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 <[email protected]>
---
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(-)

diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index 805151f..1628a5f 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 23c3190..641a5fa 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 70ed71f..e94f913 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;
--
1.7.0.1

2010-04-28 22:19:40

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 26/30] viafb: move some modesetting functions to a seperate file

From: Florian Tobias Schandinat <[email protected]>

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 <[email protected]>
---
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

diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile
index 05401b6..0dfecd2 100644
--- a/drivers/video/via/Makefile
+++ b/drivers/video/via/Makefile
@@ -7,5 +7,4 @@ obj-$(CONFIG_FB_VIA_CAMERA) += via-camera.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 1628a5f..d474fbe 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 641a5fa..a58701f 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 0000000..69ff285
--- /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 <[email protected]>
+ *
+ * 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 <linux/kernel.h>
+#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 0000000..ae35cfd
--- /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 <[email protected]>
+ *
+ * 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 <linux/types.h>
+
+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__ */
--
1.7.0.1

2010-04-28 22:19:37

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 27/30] viafb: replace inb/outb

From: Florian Tobias Schandinat <[email protected]>

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 <[email protected]>
---
drivers/video/via/hw.c | 22 +++++++---------------
1 files changed, 7 insertions(+), 15 deletions(-)

diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index d474fbe..b2bb24e 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++) {
--
1.7.0.1

2010-04-28 22:18:23

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 09/30] viafb: rework the I2C support in the VIA framebuffer driver

From: Harald Welte <[email protected]>

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 <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Harald Welte <[email protected]>
Signed-off-by: Jonathan Corbet <[email protected]>
---
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(-)

diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c
index abe59b8..be51370 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 09020f0..e19441d 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 15543e9..8f8e0bf 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 3a13242..00ed978 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 <linux/i2c.h>
#include <linux/i2c-algo-bit.h>

+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 8955ab4..fa10049 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 61b5953..4bc00ec 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 a6b3749..4589c6e 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 2a150c5..4c1314e 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
--
1.7.0.1

2010-04-28 22:20:17

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 22/30] 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.

Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/via-core.c | 232 ++++++++++++++++++++++++++++++++++++++++++
drivers/video/via/via-core.h | 29 +++++
2 files changed, 261 insertions(+), 0 deletions(-)

diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
index 432846e..83a8d34 100644
--- a/drivers/video/via/via-core.c
+++ b/drivers/video/via/via-core.c
@@ -13,6 +13,7 @@
#include "global.h"

#include <linux/module.h>
+#include <linux/interrupt.h>
#include <linux/platform_device.h>

/*
@@ -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 ba64b36..3d03141 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__ */
--
1.7.0.1

2010-04-28 22:20:38

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 21/30] 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.

Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/via-core.c | 62 +++++++++++++++++++++++++++++++++++++++++-
drivers/video/via/via-core.h | 44 +++++++++++++++++++++++++++++
2 files changed, 105 insertions(+), 1 deletions(-)

diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
index c7ce006..432846e 100644
--- a/drivers/video/via/via-core.c
+++ b/drivers/video/via/via-core.c
@@ -35,6 +35,65 @@ 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
* fbdev configuration area.
@@ -273,7 +332,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
if (ret)
goto out_teardown;
/*
- * Set up subsidiary devices
+ * Set up the framebuffer device
*/
ret = via_fb_pci_probe(&global_dev);
if (ret)
@@ -281,6 +340,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
/*
* Create our subdevices.
*/
+ viafb_int_init();
via_setup_subdevs(&global_dev);
return 0;

diff --git a/drivers/video/via/via-core.h b/drivers/video/via/via-core.h
index ac89c2a..ba64b36 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__ */
--
1.7.0.1

2010-04-28 22:20:52

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 20/30] via: Rationalize vt1636 detection

The code was ugly and didn't check whether i2c operations were succeeding;
make it a little better.

Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/vt1636.c | 20 +++++++-------------
1 files changed, 7 insertions(+), 13 deletions(-)

diff --git a/drivers/video/via/vt1636.c b/drivers/video/via/vt1636.c
index e9f3661..e5f8024 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;
--
1.7.0.1

2010-04-28 22:18:21

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 05/30] viafb: Unify duplicated set_bpp() code

As suggested by Florian: make both mode-setting paths use the same code.

Cc: Florian Tobias Schandinat <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/accel.c | 78 +++++++++++++++++++--------------------------
1 files changed, 33 insertions(+), 45 deletions(-)

diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c
index a52147c..7c1d9c4 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,
--
1.7.0.1

2010-04-28 22:18:19

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 03/30] 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 <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/viafbdev.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index 8af405b..8955ab4 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:
--
1.7.0.1

2010-04-28 22:21:12

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 19/30] viafb: Introduce viafb_find_i2c_adapter()

The camera driver will need this to look up a specific adapter.

Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/via_i2c.c | 13 +++++++++++++
drivers/video/via/via_i2c.h | 1 +
2 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c
index c88450e..febc1dd 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 1d18e7d..44532e4 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);
--
1.7.0.1

2010-04-28 22:21:20

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 18/30] 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.

Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/via_i2c.c | 14 ++++++++++----
drivers/video/via/via_i2c.h | 1 +
2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c
index 3ff60b2..c88450e 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 b2332cc..1d18e7d 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;
};
--
1.7.0.1

2010-04-28 22:21:40

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 17/30] viafb: Turn GPIO and i2c into proper platform devices

Another step toward making this thing a real multifunction device driver.

Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/via-core.c | 84 +++++++++++++++++++++++++++++++++++-------
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, 135 insertions(+), 39 deletions(-)

diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
index a2e08ac..c7ce006 100644
--- a/drivers/video/via/via-core.c
+++ b/drivers/video/via/via-core.c
@@ -190,6 +190,68 @@ 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)
+ platform_device_unregister(viafb_subdevs[i].platdev);
+}
+

static int __devinit via_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -205,6 +267,7 @@ 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)
@@ -216,19 +279,9 @@ static int __devinit via_pci_probe(struct pci_dev *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(&global_dev, adap_configs);
- if (ret) {
- via_fb_pci_remove(pdev);
- return ret;
- }
- /*
- * Create the GPIOs. We continue whether or not this succeeds;
- * the framebuffer might be useful even without GPIO ports.
+ * Create our subdevices.
*/
- ret = viafb_create_gpios(&global_dev, adap_configs);
+ via_setup_subdevs(&global_dev);
return 0;

out_teardown:
@@ -238,8 +291,7 @@ out_teardown:

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);
@@ -288,11 +340,15 @@ static int __init via_core_init(void)
if (ret)
return ret;
viafb_init();
+ viafb_i2c_init();
+ viafb_gpio_init();
return 0;
}

static void __exit via_core_exit(void)
{
+ viafb_gpio_exit();
+ viafb_i2c_exit();
viafb_exit();
pci_unregister_driver(&via_driver);
}
diff --git a/drivers/video/via/via-core.h b/drivers/video/via/via-core.h
index d004290..ac89c2a 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 6b36117..44537be 100644
--- a/drivers/video/via/via-gpio.c
+++ b/drivers/video/via/via-gpio.c
@@ -7,6 +7,7 @@

#include <linux/spinlock.h>
#include <linux/gpio.h>
+#include <linux/platform_device.h>
#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 7b53f96..8281aea 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 116fd3e..3ff60b2 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 <linux/platform_device.h>
#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 0685de9..b2332cc 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__ */
--
1.7.0.1

2010-04-28 22:21:56

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 16/30] 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 <[email protected]>
---
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(-)

diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
index 2f7eba3..a2e08ac 100644
--- a/drivers/video/via/via-core.c
+++ b/drivers/video/via/via-core.c
@@ -219,7 +219,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) {
via_fb_pci_remove(pdev);
return ret;
diff --git a/drivers/video/via/via-gpio.c b/drivers/video/via/via-gpio.c
index e119d21..6b36117 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 bcf2fe6..116fd3e 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 0093291..0685de9 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__ */
--
1.7.0.1

2010-04-28 22:22:16

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 15/30] viafb: package often used basic io functions

From: Florian Tobias Schandinat <[email protected]>

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 <[email protected]>
---
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

diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index f2425ae..805151f 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 d248f4d..23c3190 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 0000000..e1c1093
--- /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 <[email protected]>
+ *
+ * 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 <linux/types.h>
+#include <linux/io.h>
+
+/*
+ * 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__ */
--
1.7.0.1

2010-04-28 22:18:16

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 02/30] viafb: use proper pci config API

From: Harald Welte <[email protected]>

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 <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Harald Welte <[email protected]>
---
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(-)

diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index f2583b1..c94bcce 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 12ef32d..d6b25ac 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 b7018ef..8af405b 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,
--
1.7.0.1

2010-04-28 22:23:17

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 11/30] 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 <[email protected]>
Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/via_i2c.c | 19 +++++++++++++------
drivers/video/via/via_i2c.h | 1 +
2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c
index fe5535c..b5253e3 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 00ed978..73d682f 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 {
--
1.7.0.1

2010-04-28 22:22:54

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 12/30] 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.

Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/Makefile | 4 +-
drivers/video/via/dvi.c | 4 +-
drivers/video/via/global.c | 2 +
drivers/video/via/global.h | 1 +
drivers/video/via/lcd.c | 10 ++--
drivers/video/via/via-core.c | 113 ++++++++++++++++++++++++++++++++++++++++++
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 +++++-
11 files changed, 242 insertions(+), 133 deletions(-)
create mode 100644 drivers/video/via/via-core.c
create mode 100644 drivers/video/via/via-core.h

diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile
index eeed238..f644092 100644
--- a/drivers/video/via/Makefile
+++ b/drivers/video/via/Makefile
@@ -2,6 +2,6 @@
# Makefile for the VIA framebuffer driver (for Linux Kernel 2.6)
#

-obj-$(CONFIG_FB_VIA) += viafb.o
+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 be51370..e357c4d 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.c b/drivers/video/via/global.c
index 1ee511b..339d663 100644
--- a/drivers/video/via/global.c
+++ b/drivers/video/via/global.c
@@ -46,7 +46,9 @@ unsigned int viafb_second_virtual_xres;
unsigned int viafb_second_virtual_yres;
int viafb_lcd_panel_id = LCD_PANEL_ID_MAXIMUM + 1;
struct fb_info *viafbinfo;
+EXPORT_SYMBOL_GPL(viafbinfo);
struct fb_info *viafbinfo1;
struct viafb_par *viaparinfo;
+EXPORT_SYMBOL_GPL(viaparinfo);
struct viafb_par *viaparinfo1;

diff --git a/drivers/video/via/global.h b/drivers/video/via/global.h
index 8d95d5f..be48e73 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 e19441d..8ef60c0 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 0000000..cda4de4
--- /dev/null
+++ b/drivers/video/via/via-core.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+ * Copyright 2009 Jonathan Corbet <[email protected]>
+ */
+
+/*
+ * Core code for the Via multifunction framebuffer device.
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#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;
+ /*
+ * Set up subsidiary devices
+ */
+ ret = via_fb_pci_probe(pdev, ent);
+ 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) {
+ via_fb_pci_remove(pdev);
+ return ret;
+ }
+ return 0;
+}
+
+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 = pci_register_driver(&via_driver);
+ if (ret)
+ return ret;
+ viafb_init();
+ return 0;
+}
+
+static void __exit via_core_exit(void)
+{
+ viafb_exit();
+ pci_unregister_driver(&via_driver);
+}
+
+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 0000000..1c2fb06
--- /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 <[email protected]>
+ *
+ * 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 b5253e3..4788292 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 73d682f..0093291 100644
--- a/drivers/video/via/via_i2c.h
+++ b/drivers/video/via/via_i2c.h
@@ -24,39 +24,19 @@
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>

-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 fa10049..17a874f 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 4bc00ec..5604f27 100644
--- a/drivers/video/via/viafbdev.h
+++ b/drivers/video/via/viafbdev.h
@@ -24,6 +24,7 @@

#include <linux/proc_fs.h>
#include <linux/fb.h>
+#include <linux/spinlock.h>

#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__ */
--
1.7.0.1

2010-04-28 22:22:35

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 13/30] 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.

Signed-off-by: Jonathan Corbet <[email protected]>
---
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, 266 insertions(+), 184 deletions(-)

diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c
index 0d90c85..e777468 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 e357c4d..6271b76 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 be48e73..28221a0 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 2322612..f2425ae 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 d6b25ac..d248f4d 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 8ef60c0..04eec31 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 cda4de4..6f8f8e2 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 <linux/module.h>
#include <linux/platform_device.h>
-#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)
@@ -33,9 +199,19 @@ static int __devinit via_pci_probe(struct pci_dev *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_teardown;
+ /*
* Set up subsidiary devices
*/
- ret = via_fb_pci_probe(pdev, ent);
+ ret = via_fb_pci_probe(&global_dev);
if (ret)
return ret;
/*
@@ -48,12 +224,17 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
return ret;
}
return 0;
+
+out_teardown:
+ via_pci_teardown_mmio(&global_dev);
+ return ret;
}

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 1c2fb06..d004290 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 <linux/spinlock.h>
+#include <linux/pci.h>
+
/*
* 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 4788292..bcf2fe6 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 17a874f..70ed71f 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -24,6 +24,7 @@
#include <linux/stat.h>
#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 5604f27..52a35fa 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 4589c6e..e9f3661 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
--
1.7.0.1

2010-04-28 22:22:31

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 14/30] 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.

Signed-off-by: Jonathan Corbet <[email protected]>
---
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 deletions(-)
create mode 100644 drivers/video/via/via-gpio.c
create mode 100644 drivers/video/via/via-gpio.h

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 6e16244..22c1662 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 f644092..2751cb2 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 6f8f8e2..2f7eba3 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 <linux/module.h>
@@ -223,6 +224,11 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
via_fb_pci_remove(pdev);
return ret;
}
+ /*
+ * 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_teardown:
@@ -232,6 +238,7 @@ out_teardown:

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 0000000..e119d21
--- /dev/null
+++ b/drivers/video/via/via-gpio.c
@@ -0,0 +1,268 @@
+/*
+ * Support for viafb GPIO ports.
+ *
+ * Copyright 2009 Jonathan Corbet <[email protected]>
+ * Distributable under version 2 of the GNU General Public License.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/gpio.h>
+#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 0000000..7b53f96
--- /dev/null
+++ b/drivers/video/via/via-gpio.h
@@ -0,0 +1,15 @@
+/*
+ * Support for viafb GPIO ports.
+ *
+ * Copyright 2009 Jonathan Corbet <[email protected]>
+ * 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
--
1.7.0.1

2010-04-28 22:23:31

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 10/30] suppress verbose debug messages: change printk() to DEBUG_MSG()

From: Paul Fox <[email protected]>

[jc: no signoff, added my own]
Cc: Florian Tobias Schandinat <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/via_i2c.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c
index 8f8e0bf..fe5535c 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;
--
1.7.0.1

2010-04-28 22:18:12

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 01/30] viafb: Fix various resource leaks during module_init()

From: Harald Welte <[email protected]>

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 <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Harald Welte <[email protected]>
---
drivers/video/via/viafbdev.c | 52 +++++++++++++++++++++++++++++++----------
1 files changed, 39 insertions(+), 13 deletions(-)

diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index ce7783b..b7018ef 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)
--
1.7.0.1

2010-04-28 22:23:53

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 08/30] viafb: Add 1200x900 DCON/LCD panel modes for OLPC XO-1.5

From: Chris Ball <[email protected]>

[jc: extensive merge conflict fixes]
Cc: Florian Tobias Schandinat <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Chris Ball <[email protected]>
---
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 deletions(-)

diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
index ae664fb..2322612 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 de89980..c430fa2 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 1b1ccdc..09020f0 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 071f47c..9762ec6 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 d55aaa7..f974c73 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 af50e24..6f3bcda 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)},

--
1.7.0.1

2010-04-28 22:24:09

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 07/30] 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 <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/accel.c | 42 +++++++++++++++++++++++++++++++++---------
drivers/video/via/accel.h | 40 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 73 insertions(+), 9 deletions(-)

diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c
index 7c1d9c4..0d90c85 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 615c84a..2c122d2 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
--
1.7.0.1

2010-04-28 22:24:28

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 06/30] viafb: Determine type of 2D engine and store it in chip_info

From: Harald Welte <[email protected]>

This will help us for the upcoming support for 2D acceleration using
the M1 engine.

[jc: fixed merge conflicts]
Signed-off-by: Harald Welte <[email protected]>
---
drivers/video/via/chip.h | 8 ++++++++
drivers/video/via/hw.c | 15 +++++++++++++++
2 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h
index 8c06bd3..d9b6e06 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 c94bcce..ae664fb 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)
--
1.7.0.1

2010-04-28 22:24:43

by Jonathan Corbet

[permalink] [raw]
Subject: [PATCH 04/30] 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 <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/accel.c | 49 ++++++++++++++++++++++++++++++--------------
1 files changed, 33 insertions(+), 16 deletions(-)

diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c
index d5077df..a52147c 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;
--
1.7.0.1

2010-04-30 17:03:42

by Jonathan Corbet

[permalink] [raw]
Subject: Re: [RFC] Second OLPC Viafb series, v2

On Thu, 29 Apr 2010 19:26:13 +0200
Bruno Pr?mont <[email protected]> wrote:

> Testing here, loading path seems to work fine (console mode) as well as
> mode switching with fbset, but rmmod viafb fails with below trace.

OK, it looks like gpiochip_remove() is not meant to be called with IRQs
disabled. That's easily fixed. Thanks for testing!

jon

2010-04-30 17:26:22

by Bruno Prémont

[permalink] [raw]
Subject: Re: [PATCH 13/30] viafb: Separate global and fb-specific data

On Wed, 28 April 2010 Jonathan Corbet <[email protected]> wrote:
> diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
> index cda4de4..6f8f8e2 100644
> --- a/drivers/video/via/via-core.c
> +++ b/drivers/video/via/via-core.c

<snip>

> +/*
> + * 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);

Shouldn't this ioremap_nocache() have error-checking
as the one below (instead of relying on later code to bail out)?

> +
> + /*
> + * 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;

IMHO it would be better to iounmap(vdev->engine_mmio) here
instead of letting our caller run via_pci_teardown_mmio()

> + 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)
> @@ -33,9 +199,19 @@ static int __devinit via_pci_probe(struct pci_dev *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_teardown;

Why goto out_teardown here?
If via_pci_setup_mmio() failed it should undo its successful
actions itself... (see also above)

> + /*
> * Set up subsidiary devices
> */
> - ret = via_fb_pci_probe(pdev, ent);
> + ret = via_fb_pci_probe(&global_dev);
> if (ret)
> return ret;

In this case we should goto out_teardown so the mmio setup earlier gets
undone.

> /*
> @@ -48,12 +224,17 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
> return ret;
> }
> return 0;
> +
> +out_teardown:
> + via_pci_teardown_mmio(&global_dev);
> + return ret;
> }

Thanks,
Bruno

2010-04-30 17:35:38

by Bruno Prémont

[permalink] [raw]
Subject: Re: [PATCH 24/30] viafb: Add a driver for the video capture engine

Hi Jonathan,

Seems a bit confusing to me to have viafb-camera/ show up under the
PCI device when built with !CONFIG_FB_VIA_CAMERA.

On Wed, 28 April 2010 Jonathan Corbet <[email protected]> wrote:
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 22c1662..a969f76 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -1516,12 +1516,21 @@ config FB_VIA
> This is the frame buffer device driver for Graphics chips of VIA
> UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/
> CN700/VN800,CX700/VX700,P4M890) and Chrome9 Family (K8M890,CN896
> - /P4M900,VX800)
> + /P4M900,VX800,VX855)
> Say Y if you have a VIA UniChrome graphics board.
>
> To compile this driver as a module, choose M here: the
> module will be called viafb.
>
> +config FB_VIA_CAMERA
> + tristate "VIAFB camera controller support"
> + depends on FB_VIA
> + select VIDEOBUF_DMA_SG
> + help
> + Driver support for the integrated camera controller in VIA
> + Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems
> + with ov7670 sensors.
> +
> config FB_NEOMAGIC
> tristate "NeoMagic display support"
> depends on FB && PCI
> diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile
> index 2751cb2..05401b6 100644
> --- a/drivers/video/via/Makefile
> +++ b/drivers/video/via/Makefile
> @@ -3,6 +3,7 @@
> #
>
> obj-$(CONFIG_FB_VIA) += viafb.o
> +obj-$(CONFIG_FB_VIA_CAMERA) += via-camera.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 \

<snip>

> diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
> index 83a8d34..58256d0 100644
> --- a/drivers/video/via/via-core.c
> +++ b/drivers/video/via/via-core.c
> @@ -493,7 +493,10 @@ static struct viafb_subdev_info {
> },
> {
> .name = "viafb-i2c",
> - }
> + },
> + {
> + .name = "viafb-camera",
> + },
> };
> #define N_SUBDEVS ARRAY_SIZE(viafb_subdevs)
>

I think the extra 'viafb-camera' entry should be wrapped into a

#if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE)

or probably better be dynamically added when camera module is loaded
and/or detects/probes the camera sub-device.

Thanks,
Bruno

2010-04-30 17:45:43

by Bruno Prémont

[permalink] [raw]
Subject: Re: [RFC] Second OLPC Viafb series, v2

On Wed, 28 April 2010 Jonathan Corbet <[email protected]> wrote:
> This is the second posting of the second series of viafb patches. What's
> added here is a big refactoring of the driver to split its functions apart
> and the addition of code for GPIO, interrupt, DMA, and camera management.
>
> The following changes have been made since the first version:
>
> - A couple of small fixes have been made to the first series. The
> OLPC-specific tests for i2c access have been removed since they broke
> the linux-next build, and we don't try to do i2c on ports which have not
> traditionally been used that way. For that reason, I'm including that
> initial series here; the whole set applies to 2.6.34-rc3.
>
> - The build problems encountered by Florian (GPIOLIB and module stuff)
> have been fixed. I have *not* made fb/i2c/gpio into separate modules at
> this point, though that is the clear destination of this work. That's a
> bit messy and I didn't want to complicate these patches further; I will
> do it in the future.
>
> - I merged in all of Florian's cleanup patches from a couple of weeks
> ago. I've not looked at the new suspend/resume patches yet.
>
> Note that the camera driver (the last in the series) is not yet ready for
> submission; I add it here for completeness.
>
> The full series of patches can be pulled from:
>
> git://git.lwn.net/linux-2.6.git viafb-posted
>
> Some of this stuff is disruptive, and I only have one machine to test it
> all on, so I'd really appreciate it if folks with other types of hardware
> could try them out.

Testing here, loading path seems to work fine (console mode) as well as
mode switching with fbset, but rmmod viafb fails with below trace. Going
to have a look what can be the cause, looks like it's when unregistering
GPIOs.

Bruno

[ 1727.041074] ------------[ cut here ]------------
[ 1727.041232] WARNING: at /usr/src/linux-2.6-git/kernel/softirq.c:143 local_bh_enable+0x58/0x80()
[ 1727.041391] Hardware name: CX700+W697HG
[ 1727.041495] Modules linked in: e_powersaver via_cputemp snd_hda_codec_via snd_hda_intel irtty_sir hid_picolcd snd_hda_codec sir_dev backlight lcd snd_pcm irda led_class snd_timer fb_sys_
fops sysimgblt via_agp snd crc_ccitt sysfillrect syscopyarea soundcore snd_page_alloc viafb(-) i2c_algo_bit cfbcopyarea cfbimgblt cfbfillrect sg agpgart
[ 1727.043509] Pid: 1553, comm: rmmod Not tainted 2.6.34-rc5-viafb-venus #42
[ 1727.043632] Call Trace:
[ 1727.043752] [<c13371c1>] ? printk+0x18/0x1f
[ 1727.043871] [<c102a378>] ? local_bh_enable+0x58/0x80
[ 1727.044003] [<c1025b3c>] warn_slowpath_common+0x6c/0xc0
[ 1727.044127] [<c102a378>] ? local_bh_enable+0x58/0x80
[ 1727.044252] [<c1025ba5>] warn_slowpath_null+0x15/0x20
[ 1727.044375] [<c102a378>] local_bh_enable+0x58/0x80
[ 1727.044499] [<c12aabcb>] sk_filter+0x3b/0x80
[ 1727.044621] [<c12b012e>] netlink_broadcast+0x14e/0x330
[ 1727.044752] [<c1175be7>] kobject_uevent_env+0x2c7/0x380
[ 1727.044878] [<c1175caa>] kobject_uevent+0xa/0x10
[ 1727.045137] [<c11ee6b4>] device_del+0x124/0x190
[ 1727.045265] [<c11ee72b>] device_unregister+0xb/0x20
[ 1727.045390] [<c1181813>] gpiochip_remove+0xc3/0xe0
[ 1727.045511] [<c1180b10>] ? match_export+0x0/0x20
[ 1727.045677] [<f80dd67a>] viafb_gpio_remove+0x3a/0xa0 [viafb]
[ 1727.045811] [<c11f1dec>] platform_drv_remove+0xc/0x10
[ 1727.045933] [<c11f0bf1>] __device_release_driver+0x51/0xa0
[ 1727.046056] [<c11f0cb7>] driver_detach+0x77/0x80
[ 1727.046179] [<c11efee9>] bus_remove_driver+0x69/0xb0
[ 1727.046303] [<c11f11a1>] driver_unregister+0x41/0x70
[ 1727.046430] [<c11f217b>] platform_driver_unregister+0xb/0x10
[ 1727.046584] [<f80dd63d>] viafb_gpio_exit+0xd/0x10 [viafb]
[ 1727.046737] [<f80dda71>] via_core_exit+0x8/0x27 [viafb]
[ 1727.046870] [<c104ba6d>] sys_delete_module+0x18d/0x1f0
[ 1727.046994] [<c1072545>] ? do_munmap+0x225/0x290
[ 1727.047120] [<c1002b10>] sysenter_do_call+0x12/0x26
[ 1727.047237] ---[ end trace 94c40d57ecfccbc4 ]---
[ 1727.047988] ------------[ cut here ]------------
[ 1727.048105] kernel BUG at /usr/src/linux-2.6-git/mm/slub.c:2846!
[ 1727.048223] invalid opcode: 0000 [#1]
[ 1727.048381] last sysfs file: /sys/devices/platform/via_cputemp.0/temp1_input
[ 1727.048501] Modules linked in: e_powersaver via_cputemp snd_hda_codec_via snd_hda_intel irtty_sir hid_picolcd snd_hda_codec sir_dev backlight lcd snd_pcm irda led_class snd_timer fb_sys_fops sysimgblt via_agp snd crc_ccitt sysfillrect syscopyarea soundcore snd_page_alloc viafb(-) i2c_algo_bit cfbcopyarea cfbimgblt cfbfillrect sg agpgart
[ 1727.050031]
[ 1727.050031] Pid: 1553, comm: rmmod Tainted: G W 2.6.34-rc5-viafb-venus #42 CX700+W697HG/CX700+W697HG
[ 1727.050031] EIP: 0060:[<c107fadc>] EFLAGS: 00010246 CPU: 0
[ 1727.050031] EIP is at kfree+0x12c/0x130
[ 1727.050031] EAX: 80000000 EBX: c1c91c60 ECX: 00000000 EDX: c11f2530
[ 1727.050031] ESI: f80e3d60 EDI: f61ee110 EBP: f6387e40 ESP: f6387e2c
[ 1727.050031] DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 0068
[ 1727.050031] Process rmmod (pid: 1553, ti=f6387000 task=f7320000 task.ti=f6387000)
[ 1727.050031] Stack:
[ 1727.050031] f622b780 f6387e50 f6015b00 c14a73cc f61ee110 f6387e4c c11f2541 f6060840
[ 1727.050031] <0> f6387e68 c11edef9 c10c5f7b f70d3f30 f70c0c68 f70c0c68 f6015b10 f6387e7c
[ 1727.050031] <0> c117501a f6015b2c c1174fe0 f80e3150 f6387e8c c1175d8c f6015b10 f80e3150
[ 1727.050031] Call Trace:
[ 1727.050031] [<c11f2541>] ? platform_device_release+0x11/0x30
[ 1727.050031] [<c11edef9>] ? device_release+0x19/0x70
[ 1727.050031] [<c10c5f7b>] ? remove_dir+0x2b/0x40
[ 1727.050031] [<c117501a>] ? kobject_release+0x3a/0x80
[ 1727.050031] [<c1174fe0>] ? kobject_release+0x0/0x80
[ 1727.050031] [<c1175d8c>] ? kref_put+0x2c/0x60
[ 1727.050031] [<c1174f40>] ? kobject_put+0x20/0x50
[ 1727.050031] [<c11ee6e0>] ? device_del+0x150/0x190
[ 1727.050031] [<c11ed9af>] ? put_device+0xf/0x20
[ 1727.050031] [<c11f256f>] ? platform_device_put+0xf/0x20
[ 1727.050031] [<c11f2742>] ? platform_device_unregister+0x12/0x20
[ 1727.050031] [<f80ddaf8>] ? via_pci_remove+0x14/0x5c [viafb]
[ 1727.050031] [<c1187e09>] ? pci_device_remove+0x19/0x40
[ 1727.050031] [<c11f0bf1>] ? __device_release_driver+0x51/0xa0
[ 1727.050031] [<c11f0cb7>] ? driver_detach+0x77/0x80
[ 1727.050031] [<c11efee9>] ? bus_remove_driver+0x69/0xb0
[ 1727.050031] [<c11f11a1>] ? driver_unregister+0x41/0x70
[ 1727.050031] [<c10c522d>] ? sysfs_remove_file+0xd/0x10
[ 1727.050031] [<c118802d>] ? pci_unregister_driver+0x2d/0x70
[ 1727.050031] [<f80dda85>] ? via_core_exit+0x1c/0x27 [viafb]
[ 1727.050031] [<c104ba6d>] ? sys_delete_module+0x18d/0x1f0
[ 1727.050031] [<c1072545>] ? do_munmap+0x225/0x290
[ 1727.050031] [<c1002b10>] ? sysenter_do_call+0x12/0x26
[ 1727.050031] Code: 51 08 85 d2 0f 88 42 ff ff ff 8b 57 10 8b 01 89 04 16 89 31 e9 54 ff ff ff 66 a9 00 c0 74 0c 89 d8 e8 29 31 fe ff e9 46 ff ff ff <0f> 0b eb fe 55 83 e8 60 89 e5 e8 c5 fe ff ff 5d c3 8d 76 00 55
[ 1727.050031] EIP: [<c107fadc>] kfree+0x12c/0x130 SS:ESP 0068:f6387e2c
[ 1727.060774] ---[ end trace 94c40d57ecfccbc5 ]---

Subject: Re: [PATCH 13/30] viafb: Separate global and fb-specific data

Hi,

Jonathan Corbet schrieb:
> On Thu, 29 Apr 2010 20:19:02 +0200
> Bruno Pr?mont <[email protected]> wrote:
>
>>> + 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);
>> Shouldn't this ioremap_nocache() have error-checking
>> as the one below (instead of relying on later code to bail out)?
>
> It would be better, yes, I'll add a patch to fix it up.

Please don't do this. The reason for not failing in viafb is that
ioremap failure of the engine is not critical it just disables the
hardware acceleration but otherwiese it works quite nice. The problem is
that ioremap failures are quite common as we really try to remap huge
amount (sometimes above 128 or even 256 MB). In fact the bug (or missing
feature) is that the first ioremap is fatal and that needs to be fixed
on the long run. Sorry but I don't want to make viafb unusable for many
people if they don't add the "vmalloc=" kernel option so failing here
would be a step in the wrong direction.


Thanks,

Florian Tobias Schandinat

> viafb: Fix initialization error paths
>
> Properly localize error cleanup, and make sure that the iomem regions are
> unmapped if framebuffer initialization fails.
>
> Reported-by: Bruno Pr?mont <[email protected]>
> Signed-off-by: Jonathan Corbet <[email protected]>
> ---
> drivers/video/via/via-core.c | 26 ++++++++++++++++----------
> 1 files changed, 16 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
> index 2b5773a..b8a8783 100644
> --- a/drivers/video/via/via-core.c
> +++ b/drivers/video/via/via-core.c
> @@ -454,26 +454,32 @@ 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.
> */
> 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)
> + return -ENOMEM;
> /*
> - * Likewise with I/O memory.
> + * Likewise with framebuffer 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;
> + 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)
> @@ -566,13 +572,13 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
> spin_lock_init(&global_dev.reg_lock);
> ret = via_pci_setup_mmio(&global_dev);
> if (ret)
> - goto out_teardown;
> + return ret;
> /*
> * Set up the framebuffer device
> */
> ret = via_fb_pci_probe(&global_dev);
> if (ret)
> - return ret;
> + goto out_teardown;
> /*
> * Create our subdevices.
> */

2010-04-30 18:23:00

by Jonathan Corbet

[permalink] [raw]
Subject: Re: [PATCH 13/30] viafb: Separate global and fb-specific data

On Fri, 30 Apr 2010 20:07:02 +0200
Florian Tobias Schandinat <[email protected]> wrote:

> Please don't do this. The reason for not failing in viafb is that
> ioremap failure of the engine is not critical it just disables the
> hardware acceleration but otherwiese it works quite nice. The problem is
> that ioremap failures are quite common as we really try to remap huge
> amount (sometimes above 128 or even 256 MB).

But...this region is small should never be hard to remap. Are you sure
you've seen trouble with the engine region?

> In fact the bug (or missing
> feature) is that the first ioremap is fatal and that needs to be fixed
> on the long run. Sorry but I don't want to make viafb unusable for many
> people if they don't add the "vmalloc=" kernel option so failing here
> would be a step in the wrong direction.

Is the real problem, perhaps, that we're remapping the entire
framebuffer? One wonders if we could get away without doing that.
Some quick greppery suggests that the cursor code goes straight to a
small region of framebuffer memory. With working acceleration, we
shouldn't need cfb_*(). But, probably, I'm missing something?

Meanwhile, I can let initialization continue without the engine space.
It kills interrupts/dma/camera, of course, but so be it.

jon

2010-04-30 17:20:27

by Jonathan Corbet

[permalink] [raw]
Subject: Re: [PATCH 24/30] viafb: Add a driver for the video capture engine

On Thu, 29 Apr 2010 19:16:24 +0200
Bruno Prémont <[email protected]> wrote:

> I think the extra 'viafb-camera' entry should be wrapped into a
>
> #if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE)

I think you're right, yes. (As noted above, the camera driver isn't
quite ready for merging yet - but I can't swear I would have caught
this one, so I'm glad you did).

> or probably better be dynamically added when camera module is loaded
> and/or detects/probes the camera sub-device.

That's a little harder - the platform device is the means by which the
camera and the core communicate. I guess I could add a general "I'm a
via-core subdev and I'm here now" exported function in the core, but
I'm not sure that would be better than just having the platform dev be
there.

But it definitely shouldn't be around if the camera is configured out.

Thanks,

jon

Subject: Re: [PATCH 13/30] viafb: Separate global and fb-specific data

Jonathan Corbet schrieb:
> On Fri, 30 Apr 2010 20:07:02 +0200
> Florian Tobias Schandinat <[email protected]> wrote:
>
>> Please don't do this. The reason for not failing in viafb is that
>> ioremap failure of the engine is not critical it just disables the
>> hardware acceleration but otherwiese it works quite nice. The problem is
>> that ioremap failures are quite common as we really try to remap huge
>> amount (sometimes above 128 or even 256 MB).
>
> But...this region is small should never be hard to remap. Are you sure
> you've seen trouble with the engine region?

Well I agree that after the reordering you did it should more likely
work. But it remains valid that viafb can work without it and so it
should (IMHO).
Yes there were actually problems, especially since the really old code
did not even catch the error:
https://bugzilla.kernel.org/show_bug.cgi?id=13976

>> In fact the bug (or missing
>> feature) is that the first ioremap is fatal and that needs to be fixed
>> on the long run. Sorry but I don't want to make viafb unusable for many
>> people if they don't add the "vmalloc=" kernel option so failing here
>> would be a step in the wrong direction.
>
> Is the real problem, perhaps, that we're remapping the entire
> framebuffer? One wonders if we could get away without doing that.
> Some quick greppery suggests that the cursor code goes straight to a

> small region of framebuffer memory. With working acceleration, we
> shouldn't need cfb_*(). But, probably, I'm missing something?

That mostly works I just tried it once for fun. But that's probably
nothing we want to have in mainline as the hardware acceleration
functions do at least have the possibility to fail. Possible solutions
would include reducing the remapped memory on error (example: dividing
it each time by 2 and failing if not at least 4 MB could be reamapped)
or remapping it on demand: framebuffer only as big as needed (often
between 4 and 8MB) with the possibility to "grow" and the cursor. The
last would be my favourite as it does not needlessly eats memory space
but is hardest to implement. Probably it will be fixed the next time
I'll work around the memory management (which will be also tricky due to
the framebuffer interface)

> Meanwhile, I can let initialization continue without the engine space.
> It kills interrupts/dma/camera, of course, but so be it.

Yeah at least for viafb that would be nice as it does not use any of
these until now.


Thanks,

Florian Tobias Schandinat

2010-04-30 16:47:51

by Jonathan Corbet

[permalink] [raw]
Subject: Re: [PATCH 13/30] viafb: Separate global and fb-specific data

On Thu, 29 Apr 2010 20:19:02 +0200
Bruno Pr?mont <[email protected]> wrote:

> > + 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);
>
> Shouldn't this ioremap_nocache() have error-checking
> as the one below (instead of relying on later code to bail out)?

It would be better, yes, I'll add a patch to fix it up.

> > + vdev->fbmem = ioremap_nocache(vdev->fbmem_start, vdev->fbmem_len);
> > + if (vdev->fbmem == NULL)
> > + return -ENOMEM;
>
> IMHO it would be better to iounmap(vdev->engine_mmio) here
> instead of letting our caller run via_pci_teardown_mmio()

Not sure it matters, but I can make that change.

> Why goto out_teardown here?
> If via_pci_setup_mmio() failed it should undo its successful
> actions itself... (see also above)

Yes, I can fix that (see above :)

> > + /*
> > * Set up subsidiary devices
> > */
> > - ret = via_fb_pci_probe(pdev, ent);
> > + ret = via_fb_pci_probe(&global_dev);
> > if (ret)
> > return ret;
>
> In this case we should goto out_teardown so the mmio setup earlier gets
> undone.

This I'm less convinced about; as I split the functions apart, I've
tried to get away from the "all or nothing" mode of operation. Now, if
framebuffer setup fails, there will likely be very little solace in
knowing that the GPIOs still work, but I would still rather allow
things that succeed to function when possible.

That said, the code doesn't currently quite work that way. So I guess
I'll goto out_teardown here :)

jon

viafb: Fix initialization error paths

Properly localize error cleanup, and make sure that the iomem regions are
unmapped if framebuffer initialization fails.

Reported-by: Bruno Pr?mont <[email protected]>
Signed-off-by: Jonathan Corbet <[email protected]>
---
drivers/video/via/via-core.c | 26 ++++++++++++++++----------
1 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
index 2b5773a..b8a8783 100644
--- a/drivers/video/via/via-core.c
+++ b/drivers/video/via/via-core.c
@@ -454,26 +454,32 @@ 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.
*/
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)
+ return -ENOMEM;
/*
- * Likewise with I/O memory.
+ * Likewise with framebuffer 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;
+ 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)
@@ -566,13 +572,13 @@ static int __devinit via_pci_probe(struct pci_dev *pdev,
spin_lock_init(&global_dev.reg_lock);
ret = via_pci_setup_mmio(&global_dev);
if (ret)
- goto out_teardown;
+ return ret;
/*
* Set up the framebuffer device
*/
ret = via_fb_pci_probe(&global_dev);
if (ret)
- return ret;
+ goto out_teardown;
/*
* Create our subdevices.
*/
--
1.7.0.1

2010-04-30 20:02:11

by Bruno Prémont

[permalink] [raw]
Subject: Re: [PATCH 13/30] viafb: Separate global and fb-specific data

On Fri, 30 April 2010 Florian Tobias Schandinat <[email protected]> wrote:
> Jonathan Corbet schrieb:
> > On Fri, 30 Apr 2010 20:07:02 +0200
> > Florian Tobias Schandinat <[email protected]> wrote:
> >
> >> Please don't do this. The reason for not failing in viafb is that
> >> ioremap failure of the engine is not critical it just disables the
> >> hardware acceleration but otherwiese it works quite nice. The problem is
> >> that ioremap failures are quite common as we really try to remap huge
> >> amount (sometimes above 128 or even 256 MB).
> >
> > But...this region is small should never be hard to remap. Are you sure
> > you've seen trouble with the engine region?
>
> Well I agree that after the reordering you did it should more likely
> work. But it remains valid that viafb can work without it and so it
> should (IMHO).
> Yes there were actually problems, especially since the really old code
> did not even catch the error:
> https://bugzilla.kernel.org/show_bug.cgi?id=13976

Ok, but then it would help to have the comment explain that ioremap
is allowed to fail but will disable accel or what other impact it has
(probably also put similar comment at declaration of vdev->engine_mmio)

Thanks,
Bruno


> >> In fact the bug (or missing
> >> feature) is that the first ioremap is fatal and that needs to be fixed
> >> on the long run. Sorry but I don't want to make viafb unusable for many
> >> people if they don't add the "vmalloc=" kernel option so failing here
> >> would be a step in the wrong direction.
> >
> > Is the real problem, perhaps, that we're remapping the entire
> > framebuffer? One wonders if we could get away without doing that.
> > Some quick greppery suggests that the cursor code goes straight to a
>
> > small region of framebuffer memory. With working acceleration, we
> > shouldn't need cfb_*(). But, probably, I'm missing something?
>
> That mostly works I just tried it once for fun. But that's probably
> nothing we want to have in mainline as the hardware acceleration
> functions do at least have the possibility to fail. Possible solutions
> would include reducing the remapped memory on error (example: dividing
> it each time by 2 and failing if not at least 4 MB could be reamapped)
> or remapping it on demand: framebuffer only as big as needed (often
> between 4 and 8MB) with the possibility to "grow" and the cursor. The
> last would be my favourite as it does not needlessly eats memory space
> but is hardest to implement. Probably it will be fixed the next time
> I'll work around the memory management (which will be also tricky due to
> the framebuffer interface)
>
> > Meanwhile, I can let initialization continue without the engine space.
> > It kills interrupts/dma/camera, of course, but so be it.
>
> Yeah at least for viafb that would be nice as it does not use any of
> these until now.
>
>
> Thanks,
>
> Florian Tobias Schandinat