diff options
author | Dave Airlie <airlied@redhat.com> | 2010-02-23 10:03:56 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-02-23 10:03:56 +1000 |
commit | 5a0e75564d4ffe545519346449a7c3d8d15d1c96 (patch) | |
tree | 25a795f2930aaee4fced49a2887974021d9b4428 | |
parent | 9910bd1568ac84b59ff82e90b9b16571e3737f40 (diff) |
v4l2/vip hacksdrm-radeon-aiw
-rw-r--r-- | drivers/gpu/drm/radeon/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_v4l2.c | 377 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_vip.c | 137 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_vip.h | 9 |
6 files changed, 400 insertions, 135 deletions
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index a4344eee52b0..0e06bcfab67b 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -60,7 +60,7 @@ radeon-y += radeon_device.o radeon_kms.o \ rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \ r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \ r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \ - evergreen.o radeon_vip.o + evergreen.o radeon_vip.o theatre.o radeon_v4l2.o radeon-$(CONFIG_COMPAT) += radeon_ioc32.o diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 35e148f46e7e..df5c936dc992 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -709,6 +709,9 @@ enum radeon_audio_type { }; +#define RT100_ATI_ID 0x4D541002 +#define RT200_ATI_ID 0x4d4a1002 + struct radeon_mm { bool initialised; struct radeon_i2c_chan *i2c_bus; @@ -716,6 +719,11 @@ struct radeon_mm { enum radeon_tuner_type tuner_type; enum radeon_audio_type audio_type; + struct video_device *video_dev; + + int theatre_num, theatre_id; + struct list_head devlist; + // struct video_device *vbi_dev; /* TODO */ }; /* diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 0d2fe7779704..1d9ead4029fb 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -585,4 +585,6 @@ bool radeon_atom_get_multimedia(struct radeon_device *rdev); bool radeon_combios_get_multimedia(struct radeon_device *rdev); void radeon_parse_multimedia_table(struct radeon_device *rdev, uint16_t offset); +bool radeon_vip_theatre_detect(struct radeon_device *rdev); +void radeon_vip_init(struct radeon_device *rdev); #endif diff --git a/drivers/gpu/drm/radeon/radeon_v4l2.c b/drivers/gpu/drm/radeon/radeon_v4l2.c new file mode 100644 index 000000000000..4e11aaff5e53 --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_v4l2.c @@ -0,0 +1,377 @@ +#include "drmP.h" +#include "radeon_drm.h" +#include "radeon.h" + +#include <linux/videodev2.h> +#include <media/tuner.h> +#include <media/v4l2-chip-ident.h> +#include <media/i2c-addr.h> +#include <media/v4l2-common.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-device.h> +#include <media/videobuf-dma-sg.h> + +#define DRIVER_NAME "radeon" + +struct radeon_video_fh { + struct radeon_device *rdev; + enum v4l2_buf_type type; + + unsigned int width, height; +// struct videobuf_queue vidq; +}; + +void radeon_parse_multimedia_table(struct radeon_device *rdev, + uint16_t offset) +{ + uint8_t tuner, audio_chip; + uint8_t decoder_type, decoder_config; + char *dec_s = NULL; + + tuner = RBIOS8(offset); + tuner &= 0x1f; + if (tuner == 0x00 || tuner == 0x1f) + rdev->mm.tuner_type = RADEON_TUNER_NONE; + else if (tuner <= 0x10) /* lies */ + rdev->mm.tuner_type = RADEON_TUNER_FI1236; + else if (tuner <= 0x1e) /* less lies */ + rdev->mm.tuner_type = RADEON_TUNER_FRONT_BACK_9885; + + audio_chip = RBIOS8(offset + 1) & 0xf; + rdev->mm.audio_type = RADEON_AUDIO_NONE; + if (audio_chip == 0x2 || audio_chip == 0x6) + rdev->mm.audio_type = RADEON_AUDIO_TDA9850; + else if (audio_chip == 0x8 || audio_chip == 0x9) + rdev->mm.audio_type = RADEON_AUDIO_MSP34XX; + + decoder_type = RBIOS8(offset + 5) & 0xf; + if (decoder_type == 0x6) + DRM_INFO("rage theater decoder reported in BIOS\n"); + + decoder_config = RBIOS8(offset + 6) & 0x7; + switch(decoder_config) { + case 0: dec_s = "I2C"; break; + case 1: dec_s = "MPP"; break; + case 2: dec_s = "VIP 2-bit"; break; + case 3: dec_s = "VIP 4-bit"; break; + case 4: dec_s = "VIP 8-bit"; break; + case 7: dec_s = "PCI"; break; + default: + break; + } + + if (dec_s) { + DRM_INFO("Decoder configuration is %s device\n", dec_s); + } +} + +static LIST_HEAD(radeon_devlist); + +static int video_open(struct file *file) +{ + int minor = video_devdata(file)->minor; + struct radeon_video_fh *fh; + enum v4l2_buf_type type = 0; + struct radeon_device *rdev = NULL, *d; + + list_for_each_entry(d, &radeon_devlist, mm.devlist) { + if (d->mm.video_dev->minor == minor) { + rdev = d; + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } + } + if (rdev == NULL) { + return -ENODEV; + } + + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (fh == NULL) { + return -ENOMEM; + } + + file->private_data = fh; + fh->rdev = rdev; + + return 0; +} + +static ssize_t +video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) +{ + struct radeon_video_fh *fh = file->private_data; + switch (fh->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: +// if (res_locked(fh->rdev->mm.video_dev, RESOURCE_VIDEO)) +// return -EBUSY; + +// return videobuf_read_one(); + break; + default: + break; + } + return -ENOSYS; +} + +static unsigned int +video_poll(struct file *file, struct poll_table_struct *wait) +{ + unsigned int rc = POLLERR; + + rc = 0; + return rc; +} + +static int video_release(struct file *file) +{ + struct radeon_video_fh *fh = file->private_data; + + file->private_data = NULL; + kfree(fh); + return 0; +} + +static int +video_mmap(struct file *file, struct vm_area_struct * vma) +{ + return -ENOSYS; +} + +static int vidioc_querycap (struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct radeon_device *rdev = ((struct radeon_video_fh *)priv)->rdev; + strcpy(cap->driver, "radeon"); + strcpy(cap->card, "radeon"); + + cap->version = 0; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ +} + +static const struct v4l2_file_operations video_fops = { + .owner = THIS_MODULE, + .open = video_open, + .release = video_release, + .read = video_read, + .poll = video_poll, + .mmap = video_mmap, + .ioctl = video_ioctl2, +}; + +static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (unlikely(f->index >= ARRAY_SIZE(formats))) + return -EINVAL; + + strlcpy(f->description,formats[f->index].name,sizeof(f->description)); + f->pixelformat = formats[f->index].fourcc; + + return 0; +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct radeon_video_fh *fh = priv; + + f->fmt.pix.width = fh->width; + f->fmt.pix.height = fh->height; + f->fmt.pix.field = fh->vidq.field; + f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.bytesperline = (f->fmt.pix.width * fh->fmt->depth) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + return 0; +} + + +static const struct v4l2_ioctl_ops video_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, +#if 0 + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = cx8800_vbi_fmt, + .vidioc_try_fmt_vbi_cap = cx8800_vbi_fmt, + .vidioc_s_fmt_vbi_cap = cx8800_vbi_fmt, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, +#ifdef CONFIG_VIDEO_V4L1_COMPAT + .vidiocgmbuf = vidiocgmbuf, +#endif + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif +#endif +}; + +static struct video_device radeon_video_template = { + .name = "radeon-aiw", + .fops = &video_fops, + .minor = -1, + .ioctl_ops = &video_ioctl_ops, + .tvnorms = V4L2_STD_ALL, + .current_norm = V4L2_STD_NTSC_M, +}; + +struct video_device *radeon_vdev_init(struct radeon_device *rdev, + struct video_device *template, + char *type) +{ + struct video_device *vfd; + + vfd = video_device_alloc(); + if (vfd == NULL) + return NULL; + *vfd = *template; + vfd->v4l2_dev = &rdev->mm.v4l2_dev; + vfd->parent = &rdev->pdev->dev; + vfd->release = video_device_release; + snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", + "radeon", type, "radeon"); + return vfd; +} + +int radeon_v4l2_init(struct radeon_device *rdev) +{ + int err; + rdev->mm.video_dev = radeon_vdev_init(rdev, &radeon_video_template, + "video"); + err = video_register_device(rdev->mm.video_dev, VFL_TYPE_GRABBER, 0); + if (err < 0) { + printk(KERN_ERR "%s/0: can't register video device\n", + "radeon"); + goto fail_unreg; + + } + printk(KERN_INFO "%s/0: register device video%d [v4l2]\n", + "radeon", rdev->mm.video_dev->num); + + list_add_tail(&rdev->mm.devlist, &radeon_devlist); + return 0; +fail_unreg: + return err; +} + +void radeon_v4l2_fini(struct radeon_device *rdev) +{ + if (rdev->mm.video_dev) { + if (rdev->mm.video_dev->minor != -1) + video_unregister_device(rdev->mm.video_dev); + else + video_device_release(rdev->mm.video_dev); + rdev->mm.video_dev = NULL; + } + list_del(&rdev->mm.devlist); +} + +/* setup mm i2c and VIP buses and detect */ +bool radeon_multimedia_init(struct radeon_device *rdev) +{ + bool ret; + bool has_demod = false; + struct v4l2_subdev *tuner, *audio; + if (rdev->is_atom_bios) + ret = radeon_atom_get_multimedia(rdev); + else + ret = radeon_combios_get_multimedia(rdev); + + if (ret == false) + return false; + + DRM_INFO("BIOS has multimedia table\n"); + + radeon_vip_init(rdev); + radeon_vip_theatre_detect(rdev); + + if (rdev->is_atom_bios) + ret = atombios_add_mm_i2c_bus(rdev); + else + ret = radeon_combios_add_mm_i2c_bus(rdev); + if (ret == false) + return false; + + /* register V4l devices */ + strcpy(rdev->mm.v4l2_dev.name, DRIVER_NAME); + if (v4l2_device_register(NULL, &rdev->mm.v4l2_dev)) { + return false; + } + + if (rdev->mm.tuner_type == RADEON_TUNER_FRONT_BACK_9885) { + tuner = v4l2_i2c_new_subdev(&rdev->mm.v4l2_dev, + &rdev->mm.i2c_bus->adapter, + "tuner", "tuner", + 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); + + if (!tuner) + DRM_ERROR("Unable to find tuner\n"); + has_demod = true; + } + + if (rdev->mm.tuner_type != RADEON_TUNER_NONE) { + tuner = v4l2_i2c_new_subdev(&rdev->mm.v4l2_dev, + &rdev->mm.i2c_bus->adapter, + "tuner", "tuner", + 0, v4l2_i2c_tuner_addrs(has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV)); + if (!tuner) + DRM_ERROR("Unable to find tuner\n"); + } + + if (rdev->mm.audio_type == RADEON_AUDIO_MSP34XX) { + static const unsigned short addrs[] = { + I2C_ADDR_MSP3400 >> 1, + I2C_ADDR_MSP3400_ALT >> 1, + I2C_CLIENT_END + }; + audio = v4l2_i2c_new_subdev(&rdev->mm.v4l2_dev, + &rdev->mm.i2c_bus->adapter, + "msp3400", "msp3400", 0, addrs); + if (!audio) { + DRM_ERROR("Unable to locate msp3400\n"); + } + } + + ret = radeon_v4l2_init(rdev); + + rdev->mm.initialised = true; + return true; +} + + +void radeon_multimedia_fini(struct radeon_device *rdev) +{ + if (rdev->mm.initialised == false) + return; + + radeon_v4l2_fini(rdev); + + if (rdev->mm.i2c_bus) + radeon_i2c_destroy(rdev->mm.i2c_bus); + + v4l2_device_unregister(&rdev->mm.v4l2_dev); +} diff --git a/drivers/gpu/drm/radeon/radeon_vip.c b/drivers/gpu/drm/radeon/radeon_vip.c index f9e018066199..06545f16cdfa 100644 --- a/drivers/gpu/drm/radeon/radeon_vip.c +++ b/drivers/gpu/drm/radeon/radeon_vip.c @@ -2,69 +2,17 @@ #include "radeon_drm.h" #include "radeon.h" -#include <linux/videodev2.h> -#include <media/tuner.h> -#include <media/v4l2-chip-ident.h> -#include <media/i2c-addr.h> #define VIP_VIP_VENDOR_DEVICE_ID 0x0000 #define VIP_VIP_SUB_VENDOR_DEVICE_ID 0x0004 #define VIP_VIP_COMMAND_STATUS 0x0008 #define VIP_VIP_REVISION_ID 0x000c -#define RT100_ATI_ID 0x4D541002 -#define RT200_ATI_ID 0x4d4a1002 - /* Status defines */ #define VIP_BUSY 0 #define VIP_IDLE 1 #define VIP_RESET 2 /* Video Input BUS */ - -void radeon_parse_multimedia_table(struct radeon_device *rdev, - uint16_t offset) -{ - uint8_t tuner, audio_chip; - uint8_t decoder_type, decoder_config; - char *dec_s = NULL; - - tuner = RBIOS8(offset); - tuner &= 0x1f; - if (tuner == 0x00 || tuner == 0x1f) - rdev->mm.tuner_type = RADEON_TUNER_NONE; - else if (tuner <= 0x10) /* lies */ - rdev->mm.tuner_type = RADEON_TUNER_FI1236; - else if (tuner <= 0x1e) /* less lies */ - rdev->mm.tuner_type = RADEON_TUNER_FRONT_BACK_9885; - - audio_chip = RBIOS8(offset + 1) & 0xf; - rdev->mm.audio_type = RADEON_AUDIO_NONE; - if (audio_chip == 0x2 || audio_chip == 0x6) - rdev->mm.audio_type = RADEON_AUDIO_TDA9850; - else if (audio_chip == 0x8 || audio_chip == 0x9) - rdev->mm.audio_type = RADEON_AUDIO_MSP34XX; - - decoder_type = RBIOS8(offset + 5) & 0xf; - if (decoder_type == 0x6) - DRM_INFO("rage theater decoder reported in BIOS\n"); - - decoder_config = RBIOS8(offset + 6) & 0x7; - switch(decoder_config) { - case 0: dec_s = "I2C"; break; - case 1: dec_s = "MPP"; break; - case 2: dec_s = "VIP 2-bit"; break; - case 3: dec_s = "VIP 4-bit"; break; - case 4: dec_s = "VIP 8-bit"; break; - case 7: dec_s = "PCI"; break; - default: - break; - } - - if (dec_s) { - DRM_INFO("Decoder configuration is %s device\n", dec_s); - } -} - static uint32_t radeon_vip_idle(struct radeon_device *rdev) { u32 timeout; @@ -330,7 +278,7 @@ void radeon_vip_init(struct radeon_device *rdev) radeon_vip_reset(rdev); } -bool radeon_theatre_detect(struct radeon_device *rdev) +bool radeon_vip_theatre_detect(struct radeon_device *rdev) { char s[20]; uint32_t val; @@ -365,89 +313,10 @@ bool radeon_theatre_detect(struct radeon_device *rdev) if (theatre_num >= 0) { DRM_INFO("Detected Rage Theatre as device %d on VIP bus with id 0x%08x\n", theatre_num, theatre_id); + rdev->mm.theatre_num = theatre_num; + rdev->mm.theatre_id = theatre_id; return true; } return false; } -/* setup mm i2c and VIP buses and detect */ -bool radeon_multimedia_init(struct radeon_device *rdev) -{ - bool ret; - bool has_demod = false; - struct v4l2_subdev *tuner, *audio; - if (rdev->is_atom_bios) - ret = radeon_atom_get_multimedia(rdev); - else - ret = radeon_combios_get_multimedia(rdev); - - if (ret == false) - return false; - - DRM_INFO("BIOS has multimedia table\n"); - - radeon_vip_init(rdev); - radeon_theatre_detect(rdev); - - if (rdev->is_atom_bios) - ret = atombios_add_mm_i2c_bus(rdev); - else - ret = radeon_combios_add_mm_i2c_bus(rdev); - if (ret == false) - return false; -#define DRIVER_NAME "radeon" - /* register V4l devices */ - strcpy(rdev->mm.v4l2_dev.name, DRIVER_NAME); - if (v4l2_device_register(NULL, &rdev->mm.v4l2_dev)) { - return false; - } - - if (rdev->mm.tuner_type == RADEON_TUNER_FRONT_BACK_9885) { - tuner = v4l2_i2c_new_subdev(&rdev->mm.v4l2_dev, - &rdev->mm.i2c_bus->adapter, - "tuner", "tuner", - 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); - - if (!tuner) - DRM_ERROR("Unable to find tuner\n"); - has_demod = true; - } - - if (rdev->mm.tuner_type != RADEON_TUNER_NONE) { - tuner = v4l2_i2c_new_subdev(&rdev->mm.v4l2_dev, - &rdev->mm.i2c_bus->adapter, - "tuner", "tuner", - 0, v4l2_i2c_tuner_addrs(has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV)); - if (!tuner) - DRM_ERROR("Unable to find tuner\n"); - } - - if (rdev->mm.audio_type == RADEON_AUDIO_MSP34XX) { - static const unsigned short addrs[] = { - I2C_ADDR_MSP3400 >> 1, - I2C_ADDR_MSP3400_ALT >> 1, - I2C_CLIENT_END - }; - audio = v4l2_i2c_new_subdev(&rdev->mm.v4l2_dev, - &rdev->mm.i2c_bus->adapter, - "msp3400", "msp3400", 0, addrs); - if (!audio) { - DRM_ERROR("Unable to locate msp3400\n"); - } - } - - rdev->mm.initialised = true; - return true; -} - - -void radeon_multimedia_fini(struct radeon_device *rdev) -{ - if (rdev->mm.initialised == false) - return; - - if (rdev->mm.i2c_bus) - radeon_i2c_destroy(rdev->mm.i2c_bus); - - v4l2_device_unregister(&rdev->mm.v4l2_dev); -} diff --git a/drivers/gpu/drm/radeon/radeon_vip.h b/drivers/gpu/drm/radeon/radeon_vip.h new file mode 100644 index 000000000000..91b0787a7b7a --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_vip.h @@ -0,0 +1,9 @@ + +bool radeon_vip_write(struct radeon_device *rdev, uint32_t address, + uint32_t count, uint8_t *buffer); + +bool radeon_vip_read(struct radeon_device *rdev, uint32_t address, + uint32_t count, uint8_t *buffer); + + + |