diff options
author | Philippe Langlais <philippe.langlais@linaro.org> | 2012-03-19 09:23:35 +0100 |
---|---|---|
committer | Philippe Langlais <philippe.langlais@linaro.org> | 2012-03-19 09:23:35 +0100 |
commit | a541bf2c931ed9fe077b93746895249c48fe948a (patch) | |
tree | 667614e111b8f54237582b1033254dffac226e30 /drivers | |
parent | b16692467e08abab7d7971ec902cd66a9226d43b (diff) | |
parent | 68db28cd267ca26000a361e060423dd6feb1b51f (diff) |
Merge topic branch 'video' into integration-linux-ux500-3.3
Diffstat (limited to 'drivers')
65 files changed, 43905 insertions, 0 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 1a9ae1647b0..c7f39c78e7d 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -461,6 +461,24 @@ config BMP085 To compile this driver as a module, choose M here: the module will be called bmp085. +config DISPDEV + bool "Display overlay device" + depends on FB_MCDE + default n + help + This driver provides a way to use a second overlay for a display (in + addition to the framebuffer). The device allows for registration of + userspace buffers to be used with the overlay. + +config COMPDEV + bool "Display composition device" + depends on FB_MCDE && HWMEM + default n + help + This driver provides a way to use several overlays for a display. + This driver replaces the use of the framebuffer The device allows + for posting userspace buffers to be used with the overlays. + config PCH_PHUB tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB" depends on PCI diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 5317121efcd..25c8efc695d 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -48,6 +48,8 @@ obj-y += lis3lv02d/ obj-y += carma/ obj-$(CONFIG_STM_TRACE) += stm.o obj-$(CONFIG_HWMEM) += hwmem/ +obj-$(CONFIG_DISPDEV) += dispdev/ +obj-$(CONFIG_COMPDEV) += compdev/ obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o diff --git a/drivers/misc/compdev/Makefile b/drivers/misc/compdev/Makefile new file mode 100644 index 00000000000..8d5cd14dc36 --- /dev/null +++ b/drivers/misc/compdev/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_DISPDEV) += compdev.o diff --git a/drivers/misc/compdev/compdev.c b/drivers/misc/compdev/compdev.c new file mode 100644 index 00000000000..4810e20d4cd --- /dev/null +++ b/drivers/misc/compdev/compdev.c @@ -0,0 +1,539 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Display overlay compositer device driver + * + * Author: Anders Bauer <anders.bauer@stericsson.com> + * for ST-Ericsson. + * + * Modified: Per-Daniel Olsson <per-daniel.olsson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/miscdevice.h> +#include <linux/uaccess.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/ioctl.h> + +#include <linux/compdev.h> +#include <linux/hwmem.h> +#include <video/mcde_dss.h> + +static LIST_HEAD(dev_list); +static DEFINE_MUTEX(dev_list_lock); + +struct compdev_buffer { + struct hwmem_alloc *alloc; + enum compdev_ptr_type type; + u32 size; + u32 paddr; /* if pinned */ +}; + +struct compdev { + bool open; + struct mutex lock; + struct miscdevice mdev; + struct list_head list; + struct mcde_display_device *ddev; + struct mcde_overlay *ovly[NUM_COMPDEV_BUFS]; + struct compdev_buffer ovly_buffer[NUM_COMPDEV_BUFS]; + struct compdev_size phy_size; + enum mcde_display_rotation display_rotation; + enum compdev_rotation current_buffer_rotation; +}; + +static int compdev_open(struct inode *inode, struct file *file) +{ + struct compdev *cd = NULL; + + mutex_lock(&dev_list_lock); + list_for_each_entry(cd, &dev_list, list) + if (cd->mdev.minor == iminor(inode)) + break; + + if (&cd->list == &dev_list) { + mutex_unlock(&dev_list_lock); + return -ENODEV; + } + + if (cd->open) { + mutex_unlock(&dev_list_lock); + return -EBUSY; + } + + cd->open = true; + + mutex_unlock(&dev_list_lock); + + file->private_data = cd; + + return 0; +} + +static int disable_overlay(struct mcde_overlay *ovly) +{ + struct mcde_overlay_info info; + + mcde_dss_get_overlay_info(ovly, &info); + if (info.paddr != 0) { + /* Set the pointer to zero to disable the overlay */ + info.paddr = 0; + mcde_dss_apply_overlay(ovly, &info); + } + return 0; +} + +static int compdev_release(struct inode *inode, struct file *file) +{ + struct compdev *cd = NULL; + int i; + + mutex_lock(&dev_list_lock); + list_for_each_entry(cd, &dev_list, list) + if (cd->mdev.minor == iminor(inode)) + break; + mutex_unlock(&dev_list_lock); + + if (&cd->list == &dev_list) + return -ENODEV; + + for (i = 0; i < NUM_COMPDEV_BUFS; i++) { + disable_overlay(cd->ovly[i]); + if (cd->ovly_buffer[i].paddr && + cd->ovly_buffer[i].type == + COMPDEV_PTR_HWMEM_BUF_NAME_OFFSET) + hwmem_unpin(cd->ovly_buffer[i].alloc); + + cd->ovly_buffer[i].alloc = NULL; + cd->ovly_buffer[i].size = 0; + cd->ovly_buffer[i].paddr = 0; + } + + cd->open = false; + return 0; +} + +static enum mcde_ovly_pix_fmt get_ovly_fmt(enum compdev_fmt fmt) +{ + switch (fmt) { + default: + case COMPDEV_FMT_RGB565: + return MCDE_OVLYPIXFMT_RGB565; + case COMPDEV_FMT_RGB888: + return MCDE_OVLYPIXFMT_RGB888; + case COMPDEV_FMT_RGBA8888: + return MCDE_OVLYPIXFMT_RGBA8888; + case COMPDEV_FMT_RGBX8888: + return MCDE_OVLYPIXFMT_RGBX8888; + case COMPDEV_FMT_YUV422: + return MCDE_OVLYPIXFMT_YCbCr422; + } +} + +static int compdev_setup_ovly(struct compdev_img *img, + struct compdev_buffer *buffer, + struct mcde_overlay *ovly, + int z_order, + struct compdev *cd) +{ + int ret = 0; + enum hwmem_mem_type memtype; + enum hwmem_access access; + struct hwmem_mem_chunk mem_chunk; + size_t mem_chunk_length = 1; + struct hwmem_region rgn = { .offset = 0, .count = 1, .start = 0 }; + struct mcde_overlay_info info; + + if (img->buf.type == COMPDEV_PTR_HWMEM_BUF_NAME_OFFSET) { + buffer->type = COMPDEV_PTR_HWMEM_BUF_NAME_OFFSET; + buffer->alloc = hwmem_resolve_by_name(img->buf.hwmem_buf_name); + if (IS_ERR(buffer->alloc)) { + ret = PTR_ERR(buffer->alloc); + dev_warn(cd->mdev.this_device, + "HWMEM resolve failed, %d\n", ret); + goto resolve_failed; + } + + hwmem_get_info(buffer->alloc, &buffer->size, &memtype, + &access); + + if (!(access & HWMEM_ACCESS_READ) || + memtype != HWMEM_MEM_CONTIGUOUS_SYS) { + ret = -EACCES; + dev_warn(cd->mdev.this_device, + "Invalid_mem overlay, %d\n", ret); + goto invalid_mem; + } + ret = hwmem_pin(buffer->alloc, &mem_chunk, &mem_chunk_length); + if (ret) { + dev_warn(cd->mdev.this_device, + "Pin failed, %d\n", ret); + goto pin_failed; + } + + rgn.size = rgn.end = buffer->size; + ret = hwmem_set_domain(buffer->alloc, HWMEM_ACCESS_READ, + HWMEM_DOMAIN_SYNC, &rgn); + if (ret) + dev_warn(cd->mdev.this_device, + "Set domain failed, %d\n", ret); + + buffer->paddr = mem_chunk.paddr; + } else if (img->buf.type == COMPDEV_PTR_PHYSICAL) { + buffer->type = COMPDEV_PTR_PHYSICAL; + buffer->alloc = NULL; + buffer->size = img->buf.len; + buffer->paddr = img->buf.offset; + } + + info.stride = img->pitch; + info.fmt = get_ovly_fmt(img->fmt); + info.src_x = 0; + info.src_y = 0; + info.dst_x = img->dst_rect.x; + info.dst_y = img->dst_rect.y; + info.dst_z = z_order; + info.w = img->dst_rect.width; + info.h = img->dst_rect.height; + info.dirty.x = 0; + info.dirty.y = 0; + info.dirty.w = cd->phy_size.width; + info.dirty.h = cd->phy_size.height; + info.paddr = buffer->paddr; + mcde_dss_apply_overlay(ovly, &info); + return ret; + +pin_failed: +invalid_mem: + buffer->alloc = NULL; + buffer->size = 0; + buffer->paddr = 0; + +resolve_failed: + return ret; +} + +static int compdev_update_rotation(struct compdev *cd, enum compdev_rotation rotation) +{ + /* Set video mode */ + struct mcde_video_mode vmode; + int ret = 0; + + memset(&vmode, 0, sizeof(struct mcde_video_mode)); + mcde_dss_get_video_mode(cd->ddev, &vmode); + if ((cd->display_rotation + rotation) % 180) { + vmode.xres = cd->phy_size.height; + vmode.yres = cd->phy_size.width; + } else { + vmode.xres = cd->phy_size.width; + vmode.yres = cd->phy_size.height; + } + + ret = mcde_dss_set_video_mode(cd->ddev, &vmode); + if (ret != 0) + goto exit; + + /* Set rotation */ + ret = mcde_dss_set_rotation(cd->ddev, (cd->display_rotation + rotation) % 360); + if (ret != 0) + goto exit; + + /* Apply */ + ret = mcde_dss_apply_channel(cd->ddev); +exit: + return ret; +} + +static int release_prev_frame(struct compdev *cd) +{ + int ret = 0; + int i; + + /* Handle unpin of previous buffers */ + for (i = 0; i < NUM_COMPDEV_BUFS; i++) { + if (cd->ovly_buffer[i].type == + COMPDEV_PTR_HWMEM_BUF_NAME_OFFSET && + cd->ovly_buffer[i].paddr != 0) { + hwmem_unpin(cd->ovly_buffer[i].alloc); + hwmem_release(cd->ovly_buffer[i].alloc); + } + cd->ovly_buffer[i].alloc = NULL; + cd->ovly_buffer[i].size = 0; + cd->ovly_buffer[i].paddr = 0; + } + return ret; + +} + +static void check_buffer(struct compdev *cd, + struct compdev_buffer *overlay_buffer, + struct compdev_buf *posted_buffer) +{ + if (overlay_buffer->type == COMPDEV_PTR_PHYSICAL && + posted_buffer->type == COMPDEV_PTR_PHYSICAL && + overlay_buffer->paddr == posted_buffer->offset && + overlay_buffer->paddr != 0) + dev_warn(cd->mdev.this_device, "The same FB pointer!!\n"); +} + +static int compdev_post_buffers(struct compdev *cd, + struct compdev_post_buffers_req *req) +{ + int ret = 0; + int i, j; + + for (i = 0; i < NUM_COMPDEV_BUFS; i++) + for (j = 0; j < NUM_COMPDEV_BUFS; j++) + check_buffer(cd, &cd->ovly_buffer[i], + &req->img_buffers[j].buf); + + /* Unpin the previous frame */ + release_prev_frame(cd); + + /* Validate buffer count */ + if (req->buffer_count > NUM_COMPDEV_BUFS || req->buffer_count == 0) { + dev_warn(cd->mdev.this_device, + "Illegal buffer count, will be clamped to %d\n", + NUM_COMPDEV_BUFS); + req->buffer_count = NUM_COMPDEV_BUFS; + } + + /* Set channel rotation */ + if (req->buffer_count > 0 && + (cd->current_buffer_rotation != req->rotation)) { + if (compdev_update_rotation(cd, req->rotation) != 0) + dev_warn(cd->mdev.this_device, + "Failed to update MCDE rotation (req->rotation = %d), %d\n", + req->rotation, ret); + else + cd->current_buffer_rotation = req->rotation; + } + + /* Handle buffers */ + for (i = 0; i < req->buffer_count; i++) { + int overlay_index = req->buffer_count - i - 1; + ret = compdev_setup_ovly(&req->img_buffers[i], + &cd->ovly_buffer[i], cd->ovly[overlay_index], i, cd); + if (ret) + dev_warn(cd->mdev.this_device, + "Failed to setup overlay[%d], %d\n", i, ret); + } + + for (i = NUM_COMPDEV_BUFS; i > req->buffer_count; i--) + disable_overlay(cd->ovly[i-1]); + + /* Do the display update */ + if (req->buffer_count > 0) + mcde_dss_update_overlay(cd->ovly[0], false); + else + dev_warn(cd->mdev.this_device, "No overlays requested\n"); + return ret; +} + +static long compdev_ioctl(struct file *file, + unsigned int cmd, + unsigned long arg) +{ + int ret; + struct compdev *cd = (struct compdev *)file->private_data; + struct compdev_post_buffers_req req; + + mutex_lock(&cd->lock); + + switch (cmd) { + case COMPDEV_GET_SIZE_IOC: + { + struct compdev_size tmp; + if ((cd->display_rotation) % 180) { + tmp.height = cd->phy_size.width; + tmp.width = cd->phy_size.height; + } else { + tmp.height = cd->phy_size.height; + tmp.width = cd->phy_size.width; + } + ret = copy_to_user((void __user *)arg, &tmp, + sizeof(tmp)); + if (ret) + ret = -EFAULT; + } + break; + case COMPDEV_POST_BUFFERS_IOC: + /* arg is user pointer to struct compdev_post_buffers_req */ + + /* Initialize the structure */ + memset(&req, 0, sizeof(req)); + + /* + * The user request is a sub structure of the + * kernel request structure. + */ + + /* Get the user data */ + if (copy_from_user(&req, (void *)arg, sizeof(req))) { + dev_warn(cd->mdev.this_device, + "%s: copy_from_user failed\n", + __func__); + mutex_unlock(&cd->lock); + return -EFAULT; + } + + ret = compdev_post_buffers(cd, &req); + + break; + default: + ret = -ENOSYS; + } + + mutex_unlock(&cd->lock); + + return ret; +} + +static const struct file_operations compdev_fops = { + .open = compdev_open, + .release = compdev_release, + .unlocked_ioctl = compdev_ioctl, +}; + +static void init_compdev(struct compdev *cd, struct mcde_display_device *ddev, + const char *name) +{ + mutex_init(&cd->lock); + INIT_LIST_HEAD(&cd->list); + cd->ddev = ddev; + cd->mdev.minor = MISC_DYNAMIC_MINOR; + cd->mdev.name = name; + cd->mdev.fops = &compdev_fops; +} + +int compdev_create(struct mcde_display_device *ddev, + struct mcde_overlay *parent_ovly) +{ + int ret = 0; + int i; + struct compdev *cd; + struct mcde_video_mode vmode; + struct mcde_overlay_info info; + + static int counter; + char name[10]; + + cd = kzalloc(sizeof(struct compdev), GFP_KERNEL); + if (!cd) + return -ENOMEM; + + snprintf(name, sizeof(name), "%s%d", COMPDEV_DEFAULT_DEVICE_PREFIX, + counter++); + init_compdev(cd, ddev, name); + mcde_dss_get_video_mode(ddev, &vmode); + + cd->ovly[0] = parent_ovly; + if (!cd->ovly[0]) { + ret = -ENOMEM; + goto fail_create_ovly; + } + + for (i = 1; i < NUM_COMPDEV_BUFS; i++) { + cd->ovly[i] = mcde_dss_create_overlay(ddev, &info); + if (!cd->ovly[i]) { + ret = -ENOMEM; + goto fail_create_ovly; + } + mcde_dss_enable_overlay(cd->ovly[i]); + disable_overlay(cd->ovly[i]); + } + + mcde_dss_get_native_resolution(ddev, &cd->phy_size.width, + &cd->phy_size.height); + + cd->display_rotation = mcde_dss_get_rotation(ddev); + cd->current_buffer_rotation = 0; + + ret = misc_register(&cd->mdev); + if (ret) + goto fail_register_misc; + mutex_lock(&dev_list_lock); + list_add_tail(&cd->list, &dev_list); + mutex_unlock(&dev_list_lock); + + goto out; + +fail_register_misc: +fail_create_ovly: + for (i = 0; i < NUM_COMPDEV_BUFS; i++) { + if (cd->ovly[i]) + mcde_dss_destroy_overlay(cd->ovly[i]); + } + kfree(cd); +out: + return ret; +} + +void compdev_destroy(struct mcde_display_device *ddev) +{ + struct compdev *cd; + struct compdev *tmp; + int i; + + mutex_lock(&dev_list_lock); + list_for_each_entry_safe(cd, tmp, &dev_list, list) { + if (cd->ddev == ddev) { + list_del(&cd->list); + misc_deregister(&cd->mdev); + for (i = 0; i < NUM_COMPDEV_BUFS; i++) + mcde_dss_destroy_overlay(cd->ovly[i]); + kfree(cd); + break; + } + } + mutex_unlock(&dev_list_lock); +} + +static void compdev_destroy_all(void) +{ + struct compdev *cd; + struct compdev *tmp; + int i; + + mutex_lock(&dev_list_lock); + list_for_each_entry_safe(cd, tmp, &dev_list, list) { + list_del(&cd->list); + misc_deregister(&cd->mdev); + for (i = 0; i < NUM_COMPDEV_BUFS; i++) + mcde_dss_destroy_overlay(cd->ovly[i]); + kfree(cd); + } + mutex_unlock(&dev_list_lock); + + mutex_destroy(&dev_list_lock); +} + +static int __init compdev_init(void) +{ + pr_info("%s\n", __func__); + + mutex_init(&dev_list_lock); + + return 0; +} +module_init(compdev_init); + +static void __exit compdev_exit(void) +{ + compdev_destroy_all(); + pr_info("%s\n", __func__); +} +module_exit(compdev_exit); + +MODULE_AUTHOR("Anders Bauer <anders.bauer@stericsson.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Display overlay device driver"); + diff --git a/drivers/misc/dispdev/Makefile b/drivers/misc/dispdev/Makefile new file mode 100644 index 00000000000..11dc7611d26 --- /dev/null +++ b/drivers/misc/dispdev/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_DISPDEV) += dispdev.o diff --git a/drivers/misc/dispdev/dispdev.c b/drivers/misc/dispdev/dispdev.c new file mode 100644 index 00000000000..c504b69e80c --- /dev/null +++ b/drivers/misc/dispdev/dispdev.c @@ -0,0 +1,658 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Display output device driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/idr.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/miscdevice.h> +#include <linux/uaccess.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/ioctl.h> + +#include <linux/dispdev.h> +#include <linux/hwmem.h> +#include <video/mcde_dss.h> + +#define DENSITY_CHECK (16) +#define MAX_BUFFERS 4 + +static LIST_HEAD(dev_list); +static DEFINE_MUTEX(dev_list_lock); + +enum buffer_state { + BUF_UNUSED = 0, + BUF_QUEUED, + BUF_ACTIVATED, +/*TODO:waitfordone BUF_DEACTIVATED,*/ + BUF_FREE, + BUF_DEQUEUED, +}; + +struct dispdev_buffer { + struct hwmem_alloc *alloc; + u32 size; + enum buffer_state state; + u32 paddr; /* if pinned */ +}; + +struct dispdev { + bool open; + struct mutex lock; + struct miscdevice mdev; + struct list_head list; + struct mcde_display_device *ddev; + struct mcde_overlay *ovly; + struct mcde_overlay *parent_ovly; + struct dispdev_config config; + bool overlay; + struct dispdev_buffer buffers[MAX_BUFFERS]; + wait_queue_head_t waitq_dq; + /* + * For the rotation use case + * buffers_need_update is used to ensure that a set_config that + * changes width or height is followed by a unregister_buffer. + */ + bool buffers_need_update; + /* + * For the overlay startup use case. + * first_update is used to handle the first update after a set_config. + * In this case a queue_buffer will arrive after set_config and not a + * unregister_buffer as in the rotation use case. + */ + bool first_update; +}; + +static int find_buf(struct dispdev *dd, enum buffer_state state) +{ + int i; + for (i = 0; i < MAX_BUFFERS; i++) + if (dd->buffers[i].state == state) + return i; + return -1; +} + +int dispdev_open(struct inode *inode, struct file *file) +{ + int ret; + struct dispdev *dd = NULL; + + mutex_lock(&dev_list_lock); + list_for_each_entry(dd, &dev_list, list) + if (dd->mdev.minor == iminor(inode)) + break; + + if (&dd->list == &dev_list) { + mutex_unlock(&dev_list_lock); + return -ENODEV; + } + + if (dd->open) { + mutex_unlock(&dev_list_lock); + return -EBUSY; + } + + dd->open = true; + + mutex_unlock(&dev_list_lock); + + ret = mcde_dss_enable_overlay(dd->ovly); + if (ret) + return ret; + + file->private_data = dd; + + return 0; +} + +int dispdev_release(struct inode *inode, struct file *file) +{ + int i; + struct dispdev *dd = NULL; + + mutex_lock(&dev_list_lock); + list_for_each_entry(dd, &dev_list, list) + if (dd->mdev.minor == iminor(inode)) + break; + mutex_unlock(&dev_list_lock); + + if (&dd->list == &dev_list) + return -ENODEV; + + /* TODO: Make sure it waits for completion */ + mcde_dss_disable_overlay(dd->ovly); + for (i = 0; i < MAX_BUFFERS; i++) { + if (dd->buffers[i].paddr) + hwmem_unpin(dd->buffers[i].alloc); + if (dd->buffers[i].alloc) + hwmem_release(dd->buffers[i].alloc); + dd->buffers[i].alloc = NULL; + dd->buffers[i].state = BUF_UNUSED; + dd->buffers[i].size = 0; + dd->buffers[i].paddr = 0; + } + dd->open = false; + wake_up(&dd->waitq_dq); + return 0; +} + +static enum mcde_ovly_pix_fmt get_ovly_fmt(enum dispdev_fmt fmt) +{ + switch (fmt) { + default: + case DISPDEV_FMT_RGB565: + return MCDE_OVLYPIXFMT_RGB565; + case DISPDEV_FMT_RGB888: + return MCDE_OVLYPIXFMT_RGB888; + case DISPDEV_FMT_RGBA8888: + return MCDE_OVLYPIXFMT_RGBA8888; + case DISPDEV_FMT_RGBX8888: + return MCDE_OVLYPIXFMT_RGBX8888; + case DISPDEV_FMT_YUV422: + return MCDE_OVLYPIXFMT_YCbCr422; + } +} + +static void get_ovly_info(struct dispdev_config *cfg, + struct mcde_video_mode *vmode, + struct mcde_overlay_info *info, bool overlay) +{ + info->paddr = 0; + info->stride = cfg->stride; + info->fmt = get_ovly_fmt(cfg->format); + info->src_x = 0; + info->src_y = 0; + info->dst_x = cfg->x; + info->dst_y = cfg->y; + info->dst_z = cfg->z; + info->w = cfg->width; + info->h = cfg->height; + info->dirty.x = 0; + info->dirty.y = 0; + info->dirty.w = vmode->xres; + info->dirty.h = vmode->yres; +} + +static int dispdev_set_config(struct dispdev *dd, struct dispdev_config *cfg) +{ + int ret = 0; + if (memcmp(&dd->config, cfg, sizeof(struct dispdev_config)) == 0) + return 0; + + /* + * Only update MCDE if format, stride, width and height + * is the same. Otherwise just store the new config and update + * MCDE in the next queue buffer. This because the buffer that is + * active can be have the wrong format, width ... + */ + if (cfg->format == dd->config.format && + cfg->stride == dd->config.stride && + cfg->width == dd->config.width && + cfg->height == dd->config.height) { + + int buf_index; + if (!dd->buffers_need_update) { + buf_index = find_buf(dd, BUF_ACTIVATED); + if (buf_index >= 0) { + struct mcde_overlay_info info; + struct dispdev_buffer *buf; + struct mcde_video_mode vmode; + + buf = &dd->buffers[buf_index]; + mcde_dss_get_video_mode(dd->ddev, &vmode); + get_ovly_info(cfg, &vmode, &info, dd->overlay); + info.paddr = buf->paddr; + ret = mcde_dss_apply_overlay(dd->ovly, &info); + if (!ret) + mcde_dss_update_overlay(dd->ovly, + false); + } + } + } else { + dd->buffers_need_update = true; + } + + dd->config = *cfg; + + return ret; +} + +static int dispdev_register_buffer(struct dispdev *dd, s32 hwmem_name) +{ + int ret; + struct dispdev_buffer *buf; + enum hwmem_mem_type memtype; + enum hwmem_access access; + + ret = find_buf(dd, BUF_UNUSED); + if (ret < 0) + return -ENOMEM; + buf = &dd->buffers[ret]; + buf->alloc = hwmem_resolve_by_name(hwmem_name); + if (IS_ERR(buf->alloc)) { + ret = PTR_ERR(buf->alloc); + goto resolve_failed; + } + + hwmem_get_info(buf->alloc, &buf->size, &memtype, &access); + + if (!(access & HWMEM_ACCESS_READ) || + memtype != HWMEM_MEM_CONTIGUOUS_SYS) { + ret = -EACCES; + goto invalid_mem; + } + + buf->state = BUF_FREE; + goto out; +invalid_mem: + hwmem_release(buf->alloc); +resolve_failed: +out: + return ret; +} + +static int dispdev_unregister_buffer(struct dispdev *dd, u32 buf_idx) +{ + struct dispdev_buffer *buf = &dd->buffers[buf_idx]; + + if (buf_idx >= ARRAY_SIZE(dd->buffers)) + return -EINVAL; + + if (buf->state == BUF_UNUSED) + return -EINVAL; + + if (dd->buffers_need_update) + dd->buffers_need_update = false; + + if (buf->state == BUF_ACTIVATED) { + /* Disable the overlay */ + struct mcde_overlay_info info; + struct mcde_video_mode vmode; + /* TODO Wait for frame done */ + mcde_dss_get_video_mode(dd->ddev, &vmode); + get_ovly_info(&dd->config, &vmode, &info, dd->overlay); + mcde_dss_apply_overlay(dd->ovly, &info); + mcde_dss_update_overlay(dd->ovly, false); + hwmem_unpin(dd->buffers[buf_idx].alloc); + } + + hwmem_release(buf->alloc); + buf->state = BUF_UNUSED; + buf->alloc = NULL; + buf->size = 0; + buf->paddr = 0; + dd->first_update = false; + + return 0; +} + + +/** + * @brief Check if the buffer is transparent or black (ARGB = X000) + * Note: Only for ARGB32. + * Worst case: a ~full transparent buffer + * Results: ~2200us @800Mhz for a WVGA screen, with DENSITY_CHECK=8 + * ~520us @800Mhz for a WVGA screen, with DENSITY_CHECK=16 + * + * @param w witdh + * @param h height + * @param addr buffer addr + * + * @return 1 if the buffer is transparent, else 0 + */ +static int is_transparent(int w, int h, u32 *addr) +{ + int i, j; + u32 *c, *next_line; + u32 sum; + + next_line = addr; + sum = 0; + + /* TODO Optimize me */ + for (j = 0; j < h; j += DENSITY_CHECK) { + c = next_line; + for (i = 0; i < w; i += DENSITY_CHECK) { + sum += ((*c) & 0x00FFFFFF); + c += DENSITY_CHECK; + } + if (sum) + return 0; /* Not "transparent" */ + next_line += (w * DENSITY_CHECK); + } + + return 1; /* "Transparent" */ +} + +static int dispdev_queue_buffer(struct dispdev *dd, + struct dispdev_buffer_info *buffer) +{ + int ret, i; + struct mcde_overlay_info info; + struct hwmem_mem_chunk mem_chunk; + size_t mem_chunk_length = 1; + struct hwmem_region rgn = { .offset = 0, .count = 1, .start = 0 }; + struct hwmem_alloc *alloc; + struct mcde_video_mode vmode; + u32 buf_idx = buffer->buf_idx; + + if (buf_idx >= ARRAY_SIZE(dd->buffers) || + dd->buffers[buf_idx].state != BUF_DEQUEUED) + return -EINVAL; + + alloc = dd->buffers[buf_idx].alloc; + mcde_dss_get_video_mode(dd->ddev, &vmode); + get_ovly_info(&dd->config, &vmode, &info, dd->overlay); + ret = hwmem_pin(alloc, &mem_chunk, &mem_chunk_length); + if (ret) { + dev_warn(dd->mdev.this_device, "Pin failed, %d\n", ret); + return -EINVAL; + } + + rgn.size = rgn.end = dd->buffers[buf_idx].size; + ret = hwmem_set_domain(alloc, HWMEM_ACCESS_READ, + HWMEM_DOMAIN_SYNC, &rgn); + if (ret) + dev_warn(dd->mdev.this_device, "Set domain failed, %d\n", ret); + + i = find_buf(dd, BUF_ACTIVATED); + if (i >= 0) { + dd->buffers[i].state = BUF_FREE; + wake_up(&dd->waitq_dq); + } + + if (!dd->first_update) { + dd->first_update = true; + dd->buffers_need_update = false; + } + + dd->buffers[buf_idx].paddr = mem_chunk.paddr; + + if (buffer->display_update && !dd->buffers_need_update && + dd->config.width == buffer->buf_cfg.width && + dd->config.height == buffer->buf_cfg.height && + dd->config.format == buffer->buf_cfg.format && + dd->config.stride == buffer->buf_cfg.stride) { + info.paddr = mem_chunk.paddr; + mcde_dss_apply_overlay(dd->ovly, &info); + mcde_dss_update_overlay(dd->ovly, false); + } else if (buffer->display_update) { + dd->buffers_need_update = true; + } + + /* Disable the MCDE FB overlay */ + if ((dd->parent_ovly->state != NULL) && + (dd->ddev->check_transparency)) { + dd->ddev->check_transparency--; + mcde_dss_get_overlay_info(dd->parent_ovly, &info); + if (dd->ddev->check_transparency == 0) { + if (is_transparent(info.w, info.h, info.vaddr)) { + mcde_dss_disable_overlay(dd->parent_ovly); + printk(KERN_INFO "%s Disable overlay\n", + __func__); + } + } + } + + dd->buffers[buf_idx].state = BUF_ACTIVATED; + + return 0; +} + +static int dispdev_dequeue_buffer(struct dispdev *dd) +{ + int i; + + i = find_buf(dd, BUF_FREE); + if (i < 0) { + if (find_buf(dd, BUF_ACTIVATED) < 0) + return -EINVAL; + mutex_unlock(&dd->lock); + wait_event(dd->waitq_dq, (i = find_buf(dd, BUF_FREE)) >= 0); + mutex_lock(&dd->lock); + } + hwmem_unpin(dd->buffers[i].alloc); + dd->buffers[i].state = BUF_DEQUEUED; + dd->buffers[i].paddr = 0; + + return i; +} + +long dispdev_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret; + struct dispdev *dd = (struct dispdev *)file->private_data; + + mutex_lock(&dd->lock); + + switch (cmd) { + case DISPDEV_SET_CONFIG_IOC: + { + struct dispdev_config cfg; + if (copy_from_user(&cfg, (void __user *)arg, + sizeof(cfg))) + ret = -EFAULT; + else + ret = dispdev_set_config(dd, &cfg); + } + break; + case DISPDEV_GET_CONFIG_IOC: + ret = copy_to_user((void __user *)arg, &dd->config, + sizeof(dd->config)); + if (ret) + ret = -EFAULT; + break; + case DISPDEV_REGISTER_BUFFER_IOC: + ret = dispdev_register_buffer(dd, (s32)arg); + break; + case DISPDEV_UNREGISTER_BUFFER_IOC: + ret = dispdev_unregister_buffer(dd, (u32)arg); + break; + case DISPDEV_QUEUE_BUFFER_IOC: + { + struct dispdev_buffer_info buffer; + if (copy_from_user(&buffer, (void __user *)arg, + sizeof(buffer))) + ret = -EFAULT; + else + ret = dispdev_queue_buffer(dd, &buffer); + break; + } + case DISPDEV_DEQUEUE_BUFFER_IOC: + ret = dispdev_dequeue_buffer(dd); + break; + default: + ret = -ENOSYS; + } + + mutex_unlock(&dd->lock); + + return ret; +} + +static const struct file_operations dispdev_fops = { + .open = dispdev_open, + .release = dispdev_release, + .unlocked_ioctl = dispdev_ioctl, +}; + +static void init_dispdev(struct dispdev *dd, struct mcde_display_device *ddev, + const char *name, bool overlay) +{ + u16 w, h; + int rotation; + + mutex_init(&dd->lock); + INIT_LIST_HEAD(&dd->list); + dd->ddev = ddev; + dd->overlay = overlay; + mcde_dss_get_native_resolution(ddev, &w, &h); + rotation = mcde_dss_get_rotation(ddev); + + if ((rotation == MCDE_DISPLAY_ROT_90_CCW) || + (rotation == MCDE_DISPLAY_ROT_90_CW)) { + dd->config.width = h; + dd->config.height = w; + } else { + dd->config.width = w; + dd->config.height = h; + } + dd->config.format = DISPDEV_FMT_RGB565; + dd->config.stride = sizeof(u16) * w; + dd->config.x = 0; + dd->config.y = 0; + dd->config.z = 0; + dd->buffers_need_update = false; + dd->first_update = false; + init_waitqueue_head(&dd->waitq_dq); + dd->mdev.minor = MISC_DYNAMIC_MINOR; + dd->mdev.name = name; + dd->mdev.fops = &dispdev_fops; + pr_info("%s: name=%s w=%d, h=%d, fmt=%d, stride=%d\n", __func__, name, + dd->config.width, dd->config.height, dd->config.format, + dd->config.stride); +} + +int dispdev_create(struct mcde_display_device *ddev, bool overlay, + struct mcde_overlay *parent_ovly) +{ + int ret = 0; + struct dispdev *dd; + struct mcde_video_mode vmode; + struct mcde_overlay_info info = {0}; + + static int counter; + char *name = "dispdev0"; + + dd = kzalloc(sizeof(struct dispdev), GFP_KERNEL); + if (!dd) + return -ENOMEM; + + sprintf(name, "%s%d", DISPDEV_DEFAULT_DEVICE_PREFIX, counter++); + init_dispdev(dd, ddev, name, overlay); + + if (!overlay) { + ret = mcde_dss_enable_display(ddev); + if (ret) + goto fail_enable_display; + mcde_dss_get_video_mode(ddev, &vmode); + mcde_dss_try_video_mode(ddev, &vmode); + ret = mcde_dss_set_video_mode(ddev, &vmode); + if (ret) + goto fail_set_video_mode; + mcde_dss_set_pixel_format(ddev, info.fmt); + mcde_dss_apply_channel(ddev); + } else + mcde_dss_get_video_mode(ddev, &vmode); + get_ovly_info(&dd->config, &vmode, &info, overlay); + + /* Save the MCDE FB overlay */ + dd->parent_ovly = parent_ovly; + + dd->ovly = mcde_dss_create_overlay(ddev, &info); + if (!dd->ovly) { + ret = -ENOMEM; + goto fail_create_ovly; + } + + ret = misc_register(&dd->mdev); + if (ret) + goto fail_register_misc; + mutex_lock(&dev_list_lock); + list_add_tail(&dd->list, &dev_list); + mutex_unlock(&dev_list_lock); + + goto out; + +fail_register_misc: + mcde_dss_destroy_overlay(dd->ovly); +fail_create_ovly: + if (!overlay) + mcde_dss_disable_display(ddev); +fail_set_video_mode: +fail_enable_display: + kfree(dd); +out: + return ret; +} + +void dispdev_destroy(struct mcde_display_device *ddev) +{ + struct dispdev *dd; + struct dispdev *tmp; + + mutex_lock(&dev_list_lock); + list_for_each_entry_safe(dd, tmp, &dev_list, list) { + if (dd->ddev == ddev) { + list_del(&dd->list); + misc_deregister(&dd->mdev); + mcde_dss_destroy_overlay(dd->ovly); + /* + * TODO: Uncomment when DSS has reference + * counting of enable/disable + */ + /* mcde_dss_disable_display(dd->ddev); */ + kfree(dd); + break; + } + } + mutex_unlock(&dev_list_lock); +} + +static void dispdev_destroy_all(void) +{ + struct dispdev *dd; + struct dispdev *tmp; + + mutex_lock(&dev_list_lock); + list_for_each_entry_safe(dd, tmp, &dev_list, list) { + list_del(&dd->list); + misc_deregister(&dd->mdev); + mcde_dss_destroy_overlay(dd->ovly); + /* + * TODO: Uncomment when DSS has reference + * counting of enable/disable + */ + /* mcde_dss_disable_display(dd->ddev); */ + kfree(dd); + } + mutex_unlock(&dev_list_lock); + + mutex_destroy(&dev_list_lock); +} + +static int __init dispdev_init(void) +{ + pr_info("%s\n", __func__); + + mutex_init(&dev_list_lock); + + return 0; +} +module_init(dispdev_init); + +static void __exit dispdev_exit(void) +{ + dispdev_destroy_all(); + pr_info("%s\n", __func__); +} +module_exit(dispdev_exit); + +MODULE_AUTHOR("Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Display output device driver"); + diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6ca0c407c14..fe960f49b8a 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -286,6 +286,8 @@ config FB_CIRRUS Say N unless you have such a graphics board or plan to get one before you next recompile the kernel. +source "drivers/video/mcde/Kconfig" + config FB_PM2 tristate "Permedia2 support" depends on FB && ((AMIGA && BROKEN) || PCI) @@ -2413,6 +2415,8 @@ source "drivers/video/omap/Kconfig" source "drivers/video/omap2/Kconfig" source "drivers/video/backlight/Kconfig" +source "drivers/video/av8100/Kconfig" +source "drivers/video/b2r2/Kconfig" if VT source "drivers/video/console/Kconfig" diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 142606814d9..950183044f7 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -136,6 +136,9 @@ obj-$(CONFIG_FB_SH_MOBILE_MERAM) += sh_mobile_meram.o obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o obj-$(CONFIG_FB_OMAP) += omap/ obj-y += omap2/ +obj-$(CONFIG_FB_MCDE) += mcde/ +obj-$(CONFIG_AV8100) += av8100/ +obj-y += b2r2/ obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o obj-$(CONFIG_FB_CARMINE) += carminefb.o obj-$(CONFIG_FB_MB862XX) += mb862xx/ diff --git a/drivers/video/av8100/Kconfig b/drivers/video/av8100/Kconfig new file mode 100644 index 00000000000..40b9943aaa9 --- /dev/null +++ b/drivers/video/av8100/Kconfig @@ -0,0 +1,48 @@ +config AV8100 + tristate "AV8100 driver support(HDMI/CVBS)" + default n + help + Please enable this feature if hdmi/tvout driver support is required. + +config HDMI_AV8100_DEBUG + bool "HDMI and AV8100 debug messages" + default n + depends on AV8100 + ---help--- + Say Y here if you want the HDMI and AV8100 driver to + output debug messages. + +choice + prompt "AV8100 HW trig method" + default AV8100_HWTRIG_DSI_TE + +config AV8100_HWTRIG_INT + bool "AV8100 HW trig on INT" + depends on AV8100 + ---help--- + If you say Y here AV8100 will use HW triggering + from AV8100 INT to MCDE sync0. + +config AV8100_HWTRIG_I2SDAT3 + bool "AV8100 HW trig on I2SDAT3" + depends on AV8100 + ---help--- + If you say Y here AV8100 will use HW triggering + from AV8100 I2SDAT3 to MCDE sync1. + +config AV8100_HWTRIG_DSI_TE + bool "AV8100 HW trig on DSI" + depends on AV8100 + ---help--- + If you say Y here AV8100 will use HW triggering + using DSI TE polling between AV8100 and MCDE. + +config AV8100_HWTRIG_NONE + bool "AV8100 SW trig" + depends on AV8100 + ---help--- + If you say Y here AV8100 will use SW triggering + between AV8100 and MCDE. + +endchoice + diff --git a/drivers/video/av8100/Makefile b/drivers/video/av8100/Makefile new file mode 100644 index 00000000000..2d3028b18ca --- /dev/null +++ b/drivers/video/av8100/Makefile @@ -0,0 +1,10 @@ +# Make file for compiling and loadable module HDMI + +obj-$(CONFIG_AV8100) += av8100.o hdmi.o + +ifdef CONFIG_HDMI_AV8100_DEBUG +EXTRA_CFLAGS += -DDEBUG +endif + +clean-files := av8100.o hdmi.o built-in.o modules.order + diff --git a/drivers/video/av8100/av8100.c b/drivers/video/av8100/av8100.c new file mode 100644 index 00000000000..d5d159079c3 --- /dev/null +++ b/drivers/video/av8100/av8100.c @@ -0,0 +1,4166 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * + * AV8100 driver + * + * Author: Per Persson <per.xb.persson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/miscdevice.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/fs.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/kthread.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/timer.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/list.h> +#include <linux/regulator/consumer.h> +#include <linux/mfd/dbx500-prcmu.h> + +#include "av8100_regs.h" +#include <video/av8100.h> +#include <video/hdmi.h> +#include <linux/firmware.h> + +#define AV8100_FW_FILENAME "av8100.fw" +#define CUT_STR_0 "2.1" +#define CUT_STR_1 "2.2" +#define CUT_STR_3 "2.3" +#define CUT_STR_30 "3.0" +#define CUT_STR_UNKNOWN "" +#define AV8100_DEVNR_DEFAULT 0 + +/* Interrupts */ +#define AV8100_INT_EVENT 0x1 +#define AV8100_PLUGSTARTUP_EVENT 0x4 + +#define AV8100_PLUGSTARTUP_TIME 100 + +/* Standby search time */ +#define AV8100_ON_TIME 1 /* 9 ms step */ +#define AV8100_DENC_OFF_TIME 3 /* 275 ms step if > V1. Not used if V1 */ +#define AV8100_HDMI_OFF_TIME 2 /* 140 ms step if V2. 80 ms step if V1 */ + +/* Command offsets */ +#define AV8100_COMMAND_OFFSET 0x10 +#define AV8100_CUTVER_OFFSET 0x11 +#define AV8100_COMMAND_MAX_LENGTH 0x81 +#define AV8100_CMD_BUF_OFFSET (AV8100_COMMAND_OFFSET + 1) +#define AV8100_2ND_RET_BYTE_OFFSET (AV8100_COMMAND_OFFSET + 1) +#define AV8100_CEC_RET_BUF_OFFSET (AV8100_COMMAND_OFFSET + 4) +#define AV8100_HDCP_RET_BUF_OFFSET (AV8100_COMMAND_OFFSET + 2) +#define AV8100_EDID_RET_BUF_OFFSET (AV8100_COMMAND_OFFSET + 1) +#define AV8100_FUSE_CRC_OFFSET (AV8100_COMMAND_OFFSET + 2) +#define AV8100_FUSE_PRGD_OFFSET (AV8100_COMMAND_OFFSET + 3) +#define AV8100_CRC32_OFFSET (AV8100_COMMAND_OFFSET + 2) +#define AV8100_CEC_ADDR_OFFSET (AV8100_COMMAND_OFFSET + 3) + +/* Tearing effect line numbers */ +#define AV8100_TE_LINE_NB_14 14 +#define AV8100_TE_LINE_NB_17 17 +#define AV8100_TE_LINE_NB_18 18 +#define AV8100_TE_LINE_NB_21 21 +#define AV8100_TE_LINE_NB_22 22 +#define AV8100_TE_LINE_NB_24 24 +#define AV8100_TE_LINE_NB_25 25 +#define AV8100_TE_LINE_NB_26 26 +#define AV8100_TE_LINE_NB_29 29 +#define AV8100_TE_LINE_NB_30 30 +#define AV8100_TE_LINE_NB_32 32 +#define AV8100_TE_LINE_NB_38 38 +#define AV8100_TE_LINE_NB_40 40 +#define AV8100_UI_X4_DEFAULT 6 + +#define HDMI_REQUEST_FOR_REVOCATION_LIST_INPUT 2 +#define HDMI_CEC_MESSAGE_WRITE_BUFFER_SIZE 16 +#define HDMI_HDCP_SEND_KEY_SIZE 7 +#define HDMI_INFOFRAME_DATA_SIZE 28 +#define HDMI_FUSE_AES_KEY_SIZE 16 +#define HDMI_FUSE_AES_KEY_RET_SIZE 2 +#define HDMI_LOADAES_END_BLK_NR 145 +#define HDMI_CRC32_SIZE 4 +#define HDMI_HDCP_MGMT_BKSV_SIZE 5 +#define HDMI_HDCP_MGMT_SHA_SIZE 20 +#define HDMI_HDCP_MGMT_MAX_DEVICES_SIZE 20 +#define HDMI_HDCP_MGMT_DEVICE_MASK 0x7F +#define HDMI_EDIDREAD_SIZE 0x7F + +#define HPDS_INVALID 0xF +#define CPDS_INVALID 0xF +#define CECRX_INVALID 0xF + +#define REG_16_8_LSB(p) ((u8)(p & 0xFF)) +#define REG_16_8_MSB(p) ((u8)((p & 0xFF00)>>8)) +#define REG_32_8_MSB(p) ((u8)((p & 0xFF000000)>>24)) +#define REG_32_8_MMSB(p) ((u8)((p & 0x00FF0000)>>16)) +#define REG_32_8_MLSB(p) ((u8)((p & 0x0000FF00)>>8)) +#define REG_32_8_LSB(p) ((u8)(p & 0x000000FF)) +#define REG_10_8_MSB(p) ((u8)((p & 0x300)>>8)) +#define REG_12_8_MSB(p) ((u8)((p & 0xf00)>>8)) + +#define AV8100_WAITTIME_1MS 1 +#define AV8100_WAITTIME_5MS 5 +#define AV8100_WAITTIME_10MS 10 +#define AV8100_WAITTIME_50MS 50 +#define AV8100_WATTIME_100US 100 + +static DEFINE_MUTEX(av8100_hw_mutex); +#define LOCK_AV8100_HW mutex_lock(&av8100_hw_mutex) +#define UNLOCK_AV8100_HW mutex_unlock(&av8100_hw_mutex) +static DEFINE_MUTEX(av8100_fwdl_mutex); +#define LOCK_AV8100_FWDL mutex_lock(&av8100_fwdl_mutex) +#define UNLOCK_AV8100_FWDL mutex_unlock(&av8100_fwdl_mutex) + +struct color_conversion_cmd { + unsigned short c0; + unsigned short c1; + unsigned short c2; + unsigned short c3; + unsigned short c4; + unsigned short c5; + unsigned short c6; + unsigned short c7; + unsigned short c8; + unsigned short aoffset; + unsigned short boffset; + unsigned short coffset; + unsigned char lmax; + unsigned char lmin; + unsigned char cmax; + unsigned char cmin; +}; + +struct av8100_config { + struct i2c_client *client; + struct i2c_device_id *id; + struct av8100_video_input_format_cmd hdmi_video_input_cmd; + struct av8100_audio_input_format_cmd hdmi_audio_input_cmd; + struct av8100_video_output_format_cmd hdmi_video_output_cmd; + struct av8100_video_scaling_format_cmd hdmi_video_scaling_cmd; + enum av8100_color_transform color_transform; + struct av8100_cec_message_write_format_cmd + hdmi_cec_message_write_cmd; + struct av8100_cec_message_read_back_format_cmd + hdmi_cec_message_read_back_cmd; + struct av8100_denc_format_cmd hdmi_denc_cmd; + struct av8100_hdmi_cmd hdmi_cmd; + struct av8100_hdcp_send_key_format_cmd hdmi_hdcp_send_key_cmd; + struct av8100_hdcp_management_format_cmd + hdmi_hdcp_management_format_cmd; + struct av8100_infoframes_format_cmd hdmi_infoframes_cmd; + struct av8100_edid_section_readback_format_cmd + hdmi_edid_section_readback_cmd; + struct av8100_pattern_generator_format_cmd hdmi_pattern_generator_cmd; + struct av8100_fuse_aes_key_format_cmd hdmi_fuse_aes_key_cmd; +}; + +enum av8100_plug_state { + AV8100_UNPLUGGED, + AV8100_PLUGGED_STARTUP, + AV8100_PLUGGED +}; + +struct av8100_params { + int denc_off_time;/* 5 volt time */ + int hdmi_off_time;/* 5 volt time */ + int on_time;/* 5 volt time */ + u8 hpdm;/*stby_int_mask*/ + u8 cpdm;/*stby_int_mask*/ + u8 cecm;/*gen_int_mask*/ + u8 hdcpm;/*gen_int_mask*/ + u8 uovbm;/*gen_int_mask*/ + void (*hdmi_ev_cb)(enum av8100_hdmi_event); + enum av8100_plug_state plug_state; + struct clk *inputclk; + bool inputclk_requested; + bool opp_requested; + struct regulator *regulator_pwr; + bool regulator_requested; + bool pre_suspend_power; + bool ints_enabled; + bool irq_requested; +}; + +/** + * struct av8100_cea - CEA(consumer electronic access) standard structure + * @cea_id: + * @cea_nb: + * @vtotale: + **/ + +struct av8100_cea { + char cea_id[40]; + int cea_nb; + int vtotale; + int vactive; + int vsbp; + int vslen; + int vsfp; + char vpol[5]; + int htotale; + int hactive; + int hbp; + int hslen; + int hfp; + int frequence; + char hpol[5]; + int reg_line_duration; + int blkoel_duration; + int uix4; + int pll_mult; + int pll_div; +}; + +enum av8100_command_size { + AV8100_COMMAND_VIDEO_INPUT_FORMAT_SIZE = 0x17, + AV8100_COMMAND_AUDIO_INPUT_FORMAT_SIZE = 0x8, + AV8100_COMMAND_VIDEO_OUTPUT_FORMAT_SIZE = 0x1E, + AV8100_COMMAND_VIDEO_SCALING_FORMAT_SIZE = 0x11, + AV8100_COMMAND_COLORSPACECONVERSION_SIZE = 0x1D, + AV8100_COMMAND_CEC_MESSAGE_WRITE_SIZE = 0x12, + AV8100_COMMAND_CEC_MESSAGE_READ_BACK_SIZE = 0x1, + AV8100_COMMAND_DENC_SIZE = 0x6, + AV8100_COMMAND_HDMI_SIZE = 0x4, + AV8100_COMMAND_HDCP_SENDKEY_SIZE = 0xA, + AV8100_COMMAND_HDCP_MANAGEMENT_SIZE = 0x3, + AV8100_COMMAND_INFOFRAMES_SIZE = 0x21, + AV8100_COMMAND_EDID_SECTION_READBACK_SIZE = 0x3, + AV8100_COMMAND_PATTERNGENERATOR_SIZE = 0x4, + AV8100_COMMAND_FUSE_AES_KEY_SIZE = 0x12, + AV8100_COMMAND_FUSE_AES_CHK_SIZE = 0x2, +}; + +struct av8100_device { + struct list_head list; + struct miscdevice miscdev; + struct device *dev; + struct av8100_config config; + struct av8100_status status; + struct timer_list timer; + wait_queue_head_t event; + int flag; + struct av8100_params params; + u8 chip_version; +}; + +static const unsigned int waittime_retry[10] = { + 1, 2, 4, 6, 8, 10, 10, 10, 10, 10}; + +static int av8100_5V_w(u8 denc_off, u8 hdmi_off, u8 on); +static void clr_plug_status(struct av8100_device *adev, + enum av8100_plugin_status status); +static void set_plug_status(struct av8100_device *adev, + enum av8100_plugin_status status); +static void cec_rx(struct av8100_device *adev); +static void cec_tx(struct av8100_device *adev); +static void cec_txerr(struct av8100_device *adev); +static void hdcp_changed(struct av8100_device *adev); +static const struct color_conversion_cmd *get_color_transform_cmd( + struct av8100_device *adev, + enum av8100_color_transform transform); +static int av8100_open(struct inode *inode, struct file *filp); +static int av8100_release(struct inode *inode, struct file *filp); +static long av8100_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); +static int __devinit av8100_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id); +static int __devexit av8100_remove(struct i2c_client *i2c_client); + +static const struct file_operations av8100_fops = { + .owner = THIS_MODULE, + .open = av8100_open, + .release = av8100_release, + .unlocked_ioctl = av8100_ioctl +}; + +/* List of devices */ +static LIST_HEAD(av8100_device_list); + +static const struct av8100_cea av8100_all_cea[29] = { +/* cea id + * cea_nr vtot vact vsbpp vslen + * vsfp vpol htot hact hbp hslen hfp freq + * hpol rld bd uix4 pm pd */ +{ "0 CUSTOM ", + 0, 0, 0, 0, 0, + 0, "-", 800, 640, 16, 96, 10, 25200000, + "-", 0, 0, 0, 0, 0},/*Settings to be defined*/ +{ "1 CEA 1 VESA 4 640x480p @ 60 Hz ", + 1, 525, 480, 33, 2, + 10, "-", 800, 640, 49, 290, 146, 25200000, + "-", 2438, 1270, 6, 32, 1},/*RGB888*/ +{ "2 CEA 2 - 3 720x480p @ 60 Hz 4:3 ", + 2, 525, 480, 30, 6, + 9, "-", 858, 720, 34, 130, 128, 27027000, + "-", 1828, 0x3C0, 8, 24, 1},/*RGB565*/ +{ "3 CEA 4 1280x720p @ 60 Hz ", + 4, 750, 720, 20, 5, + 5, "+", 1650, 1280, 114, 39, 228, 74250000, + "+", 1706, 164, 6, 32, 1},/*RGB565*/ +{ "4 CEA 5 1920x1080i @ 60 Hz ", + 5, 1125, 540, 20, 5, + 0, "+", 2200, 1920, 88, 44, 10, 74250000, + "+", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "5 CEA 6-7 480i (NTSC) ", + 6, 525, 240, 44, 5, + 0, "-", 858, 720, 12, 64, 10, 13513513, + "-", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "6 CEA 14-15 480p @ 60 Hz ", + 14, 525, 480, 44, 5, + 0, "-", 858, 720, 12, 64, 10, 27027000, + "-", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "7 CEA 16 1920x1080p @ 60 Hz ", + 16, 1125, 1080, 36, 5, + 0, "+", 1980, 1280, 440, 40, 10, 133650000, + "+", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "8 CEA 17-18 720x576p @ 50 Hz ", + 17, 625, 576, 44, 5, + 0, "-", 864, 720, 12, 64, 10, 27000000, + "-", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "9 CEA 19 1280x720p @ 50 Hz ", + 19, 750, 720, 25, 5, + 0, "+", 1980, 1280, 440, 40, 10, 74250000, + "+", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "10 CEA 20 1920 x 1080i @ 50 Hz ", + 20, 1125, 540, 20, 5, + 0, "+", 2640, 1920, 528, 44, 10, 74250000, + "+", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "11 CEA 21-22 576i (PAL) ", + 21, 625, 288, 44, 5, + 0, "-", 1728, 1440, 12, 64, 10, 27000000, + "-", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "12 CEA 29/30 576p ", + 29, 625, 576, 44, 5, + 0, "-", 864, 720, 12, 64, 10, 27000000, + "-", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "13 CEA 31 1080p 50Hz ", + 31, 1125, 1080, 44, 5, + 0, "-", 2640, 1920, 12, 64, 10, 148500000, + "-", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "14 CEA 32 1920x1080p @ 24 Hz ", + 32, 1125, 1080, 36, 5, + 4, "+", 2750, 1920, 660, 44, 153, 74250000, + "+", 2844, 0x530, 6, 32, 1},/*RGB565*/ +{ "15 CEA 33 1920x1080p @ 25 Hz ", + 33, 1125, 1080, 36, 5, + 4, "+", 2640, 1920, 528, 44, 10, 74250000, + "+", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "16 CEA 34 1920x1080p @ 30Hz ", + 34, 1125, 1080, 36, 5, + 4, "+", 2200, 1920, 91, 44, 153, 74250000, + "+", 2275, 0xAB, 6, 32, 1},/*RGB565*/ +{ "17 CEA 60 1280x720p @ 24 Hz ", + 60, 750, 720, 20, 5, + 5, "+", 3300, 1280, 284, 50, 2276, 59400000, + "+", 4266, 0xAD0, 5, 32, 1},/*RGB565*/ +{ "18 CEA 61 1280x720p @ 25 Hz ", + 61, 750, 720, 20, 5, + 5, "+", 3960, 1280, 228, 39, 2503, 74250000, + "+", 4096, 0x500, 5, 32, 1},/*RGB565*/ +{ "19 CEA 62 1280x720p @ 30 Hz ", + 62, 750, 720, 20, 5, + 5, "+", 3300, 1280, 228, 39, 1820, 74250000, + "+", 3413, 0x770, 5, 32, 1},/*RGB565*/ +{ "20 VESA 9 800x600 @ 60 Hz ", + 109, 628, 600, 28, 4, + 0, "+", 1056, 800, 40, 128, 10, 40000000, + "+", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "21 VESA 14 848x480 @ 60 Hz ", + 114, 517, 480, 20, 5, + 0, "+", 1088, 848, 24, 80, 10, 33750000, + "-", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "22 VESA 16 1024x768 @ 60 Hz ", + 116, 806, 768, 38, 6, + 0, "-", 1344, 1024, 24, 135, 10, 65000000, + "-", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "23 VESA 22 1280x768 @ 60 Hz ", + 122, 790, 768, 34, 4, + 0, "+", 1440, 1280, 48, 160, 10, 68250000, + "-", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "24 VESA 23 1280x768 @ 60 Hz ", + 123, 798, 768, 30, 7, + 0, "+", 1664, 1280, 64, 128, 10, 79500000, + "-", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "25 VESA 27 1280x800 @ 60 Hz ", + 127, 823, 800, 23, 6, + 0, "+", 1440, 1280, 48, 32, 10, 71000000, + "+", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "26 VESA 28 1280x800 @ 60 Hz ", + 128, 831, 800, 31, 6, + 0, "+", 1680, 1280, 72, 128, 10, 83500000, + "-", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "27 VESA 39 1360x768 @ 60 Hz ", + 139, 795, 768, 22, 5, + 0, "-", 1792, 1360, 48, 32, 10, 85500000, + "+", 0, 0, 0, 0, 0},/*Settings to be define*/ +{ "28 VESA 81 1366x768 @ 60 Hz ", + 181, 798, 768, 30, 5, + 0, "+", 1792, 1366, 72, 136, 10, 85750000, + "-", 0, 0, 0, 0, 0} /*Settings to be define*/ +}; + +const struct color_conversion_cmd col_trans_identity = { + .c0 = 0x0100, .c1 = 0x0000, .c2 = 0x0000, + .c3 = 0x0000, .c4 = 0x0100, .c5 = 0x0000, + .c6 = 0x0000, .c7 = 0x0000, .c8 = 0x0100, + .aoffset = 0x0000, .boffset = 0x0000, .coffset = 0x0000, + .lmax = 0xff, + .lmin = 0x00, + .cmax = 0xff, + .cmin = 0x00, +}; + +const struct color_conversion_cmd col_trans_identity_clamp_yuv = { + .c0 = 0x0100, .c1 = 0x0000, .c2 = 0x0000, + .c3 = 0x0000, .c4 = 0x0100, .c5 = 0x0000, + .c6 = 0x0000, .c7 = 0x0000, .c8 = 0x0100, + .aoffset = 0x0000, .boffset = 0x0000, .coffset = 0x0000, + .lmax = 0xeb, + .lmin = 0x10, + .cmax = 0xf0, + .cmin = 0x10, +}; + +const struct color_conversion_cmd col_trans_yuv_to_rgb_v1 = { + .c0 = 0x0087, .c1 = 0x0000, .c2 = 0x00ba, + .c3 = 0x0087, .c4 = 0xffd3, .c5 = 0xffa1, + .c6 = 0x0087, .c7 = 0x00eb, .c8 = 0x0000, + .aoffset = 0xffab, .boffset = 0x004e, .coffset = 0xff92, + .lmax = 0xff, + .lmin = 0x00, + .cmax = 0xff, + .cmin = 0x00, +}; + +const struct color_conversion_cmd col_trans_yuv_to_rgb_v2 = { + .c0 = 0x0198, .c1 = 0x012a, .c2 = 0x0000, + .c3 = 0xff30, .c4 = 0x012a, .c5 = 0xff9c, + .c6 = 0x0000, .c7 = 0x012a, .c8 = 0x0204, + .aoffset = 0xff21, .boffset = 0x0088, .coffset = 0xfeeb, + .lmax = 0xff, + .lmin = 0x00, + .cmax = 0xff, + .cmin = 0x00, +}; + +const struct color_conversion_cmd col_trans_yuv_to_denc = { + .c0 = 0x0100, .c1 = 0x0000, .c2 = 0x0000, + .c3 = 0x0000, .c4 = 0x0100, .c5 = 0x0000, + .c6 = 0x0000, .c7 = 0x0000, .c8 = 0x0100, + .aoffset = 0x0000, .boffset = 0x0000, .coffset = 0x0000, + .lmax = 0xeb, + .lmin = 0x10, + .cmax = 0xf0, + .cmin = 0x10, +}; + +const struct color_conversion_cmd col_trans_rgb_to_denc = { + .c0 = 0x0070, .c1 = 0xffb6, .c2 = 0xffda, + .c3 = 0x0042, .c4 = 0x0081, .c5 = 0x0019, + .c6 = 0xffee, .c7 = 0xffa2, .c8 = 0x0070, + .aoffset = 0x007f, .boffset = 0x0010, .coffset = 0x007f, + .lmax = 0xff, + .lmin = 0x00, + .cmax = 0xff, + .cmin = 0x00, +}; + +static const struct i2c_device_id av8100_id[] = { + { "av8100", 0 }, + { } +}; + +static struct av8100_device *devnr_to_adev(int devnr) +{ + /* Get device from list of devices */ + struct list_head *element; + struct av8100_device *av8100_dev; + int cnt = 0; + + list_for_each(element, &av8100_device_list) { + av8100_dev = list_entry(element, struct av8100_device, list); + if (cnt == devnr) + return av8100_dev; + cnt++; + } + + return NULL; +} + +static struct av8100_device *dev_to_adev(struct device *dev) +{ + /* Get device from list of devices */ + struct list_head *element; + struct av8100_device *av8100_dev; + int cnt = 0; + + list_for_each(element, &av8100_device_list) { + av8100_dev = list_entry(element, struct av8100_device, list); + if (av8100_dev->dev == dev) + return av8100_dev; + cnt++; + } + + return NULL; +} + +static int adev_to_devnr(struct av8100_device *adev) +{ + /* Get devnr from list of devices */ + struct list_head *element; + struct av8100_device *av8100_dev; + int cnt = 0; + + list_for_each(element, &av8100_device_list) { + av8100_dev = list_entry(element, struct av8100_device, list); + if (av8100_dev == adev) + return cnt; + cnt++; + } + + return -EINVAL; +} + +#ifdef CONFIG_PM +static int av8100_suspend(struct device *dev) +{ + int ret = 0; + struct av8100_device *adev; + + adev = dev_to_adev(dev); + if (!adev) + return -EFAULT; + + dev_dbg(dev, "%s\n", __func__); + + adev->params.pre_suspend_power = + (av8100_status_get().av8100_state > AV8100_OPMODE_SHUTDOWN); + + if (adev->params.pre_suspend_power) { + ret = av8100_powerdown(); + if (ret) + dev_err(dev, "av8100_powerdown failed\n"); + } + + return ret; +} + +static int av8100_resume(struct device *dev) +{ + int ret; + u8 hpds = 0; + struct av8100_device *adev; + + adev = dev_to_adev(dev); + if (!adev) + return -EFAULT; + + dev_dbg(dev, "%s\n", __func__); + + if (adev->params.pre_suspend_power) { + ret = av8100_powerup(); + if (ret) { + dev_err(dev, "av8100_powerup failed\n"); + return ret; + } + + /* Check HDMI plug status */ + if (av8100_reg_stby_r(NULL, NULL, &hpds, NULL, NULL)) { + dev_warn(dev, "av8100_reg_stby_r failed\n"); + goto av8100_resume_end; + } + + if (hpds) + set_plug_status(adev, AV8100_HDMI_PLUGIN); /* Plugged*/ + else + clr_plug_status(adev, + AV8100_HDMI_PLUGIN); /* Unplugged*/ + + adev->params.hpdm = AV8100_STANDBY_INTERRUPT_MASK_HPDM_HIGH; + av8100_enable_interrupt(); + } + +av8100_resume_end: + return 0; +} + +static const struct dev_pm_ops av8100_dev_pm_ops = { + .suspend = av8100_suspend, + .resume = av8100_resume, +}; +#endif + +static struct i2c_driver av8100_driver = { + .probe = av8100_probe, + .remove = av8100_remove, + .driver = { + .name = "av8100", +#ifdef CONFIG_PM + .pm = &av8100_dev_pm_ops, +#endif + }, + .id_table = av8100_id, +}; + +static void av8100_plugtimer_int(unsigned long value) +{ + struct av8100_device *adev; + + adev = devnr_to_adev((int)value); + adev->flag |= AV8100_PLUGSTARTUP_EVENT; + wake_up_interruptible(&adev->event); + del_timer(&adev->timer); +} + +static int av8100_int_event_handle(struct av8100_device *adev) +{ + u8 hpdi = 0; + u8 cpdi = 0; + u8 uovbi = 0; + u8 hdcpi = 0; + u8 ceci = 0; + u8 hpds = 0; + u8 cpds = 0; + u8 hdcps = 0; + u8 onuvb = 0; + u8 cectxerr = 0; + u8 cecrx = 0; + u8 cectx = 0; + + /* STANDBY_PENDING_INTERRUPT reg */ + if (av8100_reg_stby_pend_int_r(&hpdi, &cpdi, NULL, NULL)) { + dev_dbg(adev->dev, "av8100_reg_stby_pend_int_r failed\n"); + goto av8100_int_event_handle_1; + } + + /* Plug event */ + if (hpdi | cpdi) { + /* Clear pending interrupts */ + (void)av8100_reg_stby_pend_int_w(1, 1, 1, 0); + + /* STANDBY reg */ + if (av8100_reg_stby_r(NULL, NULL, &hpds, &cpds, NULL)) { + dev_dbg(adev->dev, "av8100_reg_stby_r failed\n"); + goto av8100_int_event_handle_1; + } + } + + if (cpdi & adev->params.cpdm) { + /* TVout plugin change */ + if (cpds) { + dev_dbg(adev->dev, "cpds 1\n"); + set_plug_status(adev, AV8100_CVBS_PLUGIN); + } else { + dev_dbg(adev->dev, "cpds 0\n"); + clr_plug_status(adev, AV8100_CVBS_PLUGIN); + } + } + + if (hpdi & adev->params.hpdm) { + /* HDMI plugin change */ + if (hpds) { + /* Plugged */ + /* Set 5V always on */ + av8100_5V_w(adev->params.denc_off_time, + 0, + adev->params.on_time); + dev_dbg(adev->dev, "hpds 1\n"); + set_plug_status(adev, AV8100_HDMI_PLUGIN); + } else { + /* Unplugged */ + av8100_5V_w(adev->params.denc_off_time, + adev->params.hdmi_off_time, + adev->params.on_time); + dev_dbg(adev->dev, "hpds 0\n"); + clr_plug_status(adev, AV8100_HDMI_PLUGIN); + } + } + +av8100_int_event_handle_1: + /* GENERAL_INTERRUPT reg */ + if (av8100_reg_gen_int_r(NULL, NULL, NULL, &ceci, + &hdcpi, &uovbi, NULL)) { + dev_dbg(adev->dev, "av8100_reg_gen_int_r failed\n"); + return -EINVAL; + } + + /* CEC or HDCP event */ + if (ceci | hdcpi | uovbi) { + /* Clear pending interrupts */ + av8100_reg_gen_int_w(1, 1, 1, 1, 1, 1); + + /* GENERAL_STATUS reg */ + if (av8100_reg_gen_status_r(&cectxerr, &cecrx, &cectx, NULL, + &onuvb, &hdcps) != 0) { + dev_dbg(adev->dev, "av8100_reg_gen_status_r fail\n"); + return -EINVAL; + } + } + + /* Underflow or overflow */ + if (uovbi) + dev_dbg(adev->dev, "uovbi %d\n", onuvb); + + /* CEC received */ + if (ceci && cecrx) { + u8 val; + + dev_dbg(adev->dev, "cecrx\n"); + + /* Clear cecrx in status reg*/ + if (av8100_reg_r(AV8100_GENERAL_STATUS, &val) == 0) { + if (av8100_reg_w(AV8100_GENERAL_STATUS, + val & ~AV8100_GENERAL_STATUS_CECREC_MASK)) + dev_info(adev->dev, "gen_stat write error\n"); + } else { + dev_info(adev->dev, "gen_stat read error\n"); + } + + /* Report CEC event */ + cec_rx(adev); + } + + /* CEC tx error */ + if (ceci && cectx && cectxerr) { + dev_dbg(adev->dev, "cectxerr\n"); + /* Report CEC tx error event */ + cec_txerr(adev); + } else if (ceci && cectx) { + dev_dbg(adev->dev, "cectx\n"); + /* Report CEC tx event */ + cec_tx(adev); + } + + /* HDCP event */ + if (hdcpi) { + dev_dbg(adev->dev, "hdcpch:%0x\n", hdcps); + /* Report HDCP status change event */ + hdcp_changed(adev); + } + + return 0; +} + +static int av8100_plugstartup_event_handle(struct av8100_device *adev) +{ + u8 hpds = 0; + u8 cpds = 0; + + switch (adev->params.plug_state) { + case AV8100_UNPLUGGED: + case AV8100_PLUGGED: + default: + break; + + case AV8100_PLUGGED_STARTUP: + /* Unmask interrupt */ + adev->params.hpdm = AV8100_STANDBY_INTERRUPT_MASK_HPDM_HIGH; + if (av8100_reg_stby_int_mask_w(adev->params.hpdm, + adev->params.cpdm, + AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_INPUT, + AV8100_STANDBY_INTERRUPT_MASK_IPOL_LOW)) { + dev_dbg(adev->dev, + "av8100_reg_stby_int_mask_w fail\n"); + } + + mdelay(AV8100_WAITTIME_1MS); + + /* Get actual plug status */ + if (av8100_reg_stby_r(NULL, NULL, &hpds, &cpds, NULL)) + dev_dbg(adev->dev, "av8100_reg_stby_r fail\n"); + + /* Set plugstate */ + if (hpds) { + adev->params.plug_state = AV8100_PLUGGED; + dev_dbg(adev->dev, "plug_state:2\n"); + } else { + adev->params.plug_state = AV8100_UNPLUGGED; + dev_dbg(adev->dev, "plug_state:0\n"); + + if (adev->params.hdmi_ev_cb) + adev->params.hdmi_ev_cb( + AV8100_HDMI_EVENT_HDMI_PLUGOUT); + } + break; + } + + return 0; +} + +static int av8100_thread(void *p) +{ + u8 flags; + struct av8100_device *adev = p; + + while (1) { + wait_event_interruptible(adev->event, (adev->flag != 0)); + flags = adev->flag; + adev->flag = 0; + + if (adev->status.av8100_state < AV8100_OPMODE_STANDBY) + continue; + + if (flags & AV8100_INT_EVENT) + (void)av8100_int_event_handle(adev); + + if (flags & AV8100_PLUGSTARTUP_EVENT) + (void)av8100_plugstartup_event_handle(adev); + } + + return 0; +} + +static irqreturn_t av8100_intr_handler(int irq, void *p) +{ + struct av8100_device *adev; + + adev = (struct av8100_device *) p; + adev->flag |= AV8100_INT_EVENT; + wake_up_interruptible(&adev->event); + + return IRQ_HANDLED; +} + +static u16 av8100_get_te_line_nb( + enum av8100_output_CEA_VESA output_video_format) +{ + u16 retval; + + switch (output_video_format) { + case AV8100_CEA1_640X480P_59_94HZ: + case AV8100_CEA2_3_720X480P_59_94HZ: + case AV8100_VESA16_1024X768P_60HZ: + retval = AV8100_TE_LINE_NB_30; + break; + + case AV8100_CEA4_1280X720P_60HZ: + case AV8100_CEA60_1280X720P_24HZ: + case AV8100_CEA61_1280X720P_25HZ: + case AV8100_CEA62_1280X720P_30HZ: + retval = AV8100_TE_LINE_NB_21; + break; + + case AV8100_CEA5_1920X1080I_60HZ: + case AV8100_CEA6_7_NTSC_60HZ: + case AV8100_CEA20_1920X1080I_50HZ: + case AV8100_CEA21_22_576I_PAL_50HZ: + case AV8100_VESA27_1280X800P_59_91HZ: + retval = AV8100_TE_LINE_NB_18; + break; + + case AV8100_CEA14_15_480p_60HZ: + retval = AV8100_TE_LINE_NB_32; + break; + + case AV8100_CEA17_18_720X576P_50HZ: + case AV8100_CEA29_30_576P_50HZ: + retval = AV8100_TE_LINE_NB_40; + break; + + case AV8100_CEA19_1280X720P_50HZ: + case AV8100_VESA39_1360X768P_60_02HZ: + retval = AV8100_TE_LINE_NB_22; + break; + + case AV8100_CEA32_1920X1080P_24HZ: + case AV8100_CEA33_1920X1080P_25HZ: + case AV8100_CEA34_1920X1080P_30HZ: + retval = AV8100_TE_LINE_NB_38; + break; + + case AV8100_VESA9_800X600P_60_32HZ: + retval = AV8100_TE_LINE_NB_24; + break; + + case AV8100_VESA14_848X480P_60HZ: + retval = AV8100_TE_LINE_NB_29; + break; + + case AV8100_VESA22_1280X768P_59_99HZ: + retval = AV8100_TE_LINE_NB_17; + break; + + case AV8100_VESA23_1280X768P_59_87HZ: + case AV8100_VESA81_1366X768P_59_79HZ: + retval = AV8100_TE_LINE_NB_25; + break; + + case AV8100_VESA28_1280X800P_59_81HZ: + retval = AV8100_TE_LINE_NB_26; + break; + + case AV8100_CEA16_1920X1080P_60HZ: + case AV8100_CEA31_1920x1080P_50Hz: + default: + /* TODO */ + retval = AV8100_TE_LINE_NB_38; + break; + } + + return retval; +} + +static u16 av8100_get_ui_x4( + enum av8100_output_CEA_VESA output_video_format) +{ + return AV8100_UI_X4_DEFAULT; +} + +static int av8100_config_video_output_dep( + enum av8100_output_CEA_VESA output_format) +{ + int retval; + union av8100_configuration config; + + /* video input */ + config.video_input_format.dsi_input_mode = + AV8100_HDMI_DSI_COMMAND_MODE; + config.video_input_format.input_pixel_format = AV8100_INPUT_PIX_RGB565; + config.video_input_format.total_horizontal_pixel = + av8100_all_cea[output_format].htotale; + config.video_input_format.total_horizontal_active_pixel = + av8100_all_cea[output_format].hactive; + config.video_input_format.total_vertical_lines = + av8100_all_cea[output_format].vtotale; + config.video_input_format.total_vertical_active_lines = + av8100_all_cea[output_format].vactive; + + switch (output_format) { + case AV8100_CEA5_1920X1080I_60HZ: + case AV8100_CEA20_1920X1080I_50HZ: + case AV8100_CEA21_22_576I_PAL_50HZ: + case AV8100_CEA6_7_NTSC_60HZ: + config.video_input_format.video_mode = + AV8100_VIDEO_INTERLACE; + break; + + default: + config.video_input_format.video_mode = + AV8100_VIDEO_PROGRESSIVE; + break; + } + + config.video_input_format.nb_data_lane = + AV8100_DATA_LANES_USED_2; + config.video_input_format.nb_virtual_ch_command_mode = 0; + config.video_input_format.nb_virtual_ch_video_mode = 0; + config.video_input_format.ui_x4 = av8100_get_ui_x4(output_format); + config.video_input_format.TE_line_nb = av8100_get_te_line_nb( + output_format); + config.video_input_format.TE_config = AV8100_TE_OFF; + config.video_input_format.master_clock_freq = 0; + + retval = av8100_conf_prep( + AV8100_COMMAND_VIDEO_INPUT_FORMAT, &config); + if (retval) + return -EFAULT; + + /* DENC */ + switch (output_format) { + case AV8100_CEA21_22_576I_PAL_50HZ: + config.denc_format.cvbs_video_format = AV8100_CVBS_625; + config.denc_format.standard_selection = AV8100_PAL_BDGHI; + break; + + case AV8100_CEA6_7_NTSC_60HZ: + config.denc_format.cvbs_video_format = AV8100_CVBS_525; + config.denc_format.standard_selection = AV8100_NTSC_M; + break; + + default: + /* Not supported */ + break; + } + + return 0; +} + +static int av8100_config_init(struct av8100_device *adev) +{ + int retval; + union av8100_configuration config; + + dev_dbg(adev->dev, "%s\n", __func__); + + memset(&config, 0, sizeof(union av8100_configuration)); + memset(&adev->config, 0, sizeof(struct av8100_config)); + + /* Color conversion */ + config.color_transform = AV8100_COLOR_TRANSFORM_INDENTITY; + retval = av8100_conf_prep( + AV8100_COMMAND_COLORSPACECONVERSION, &config); + if (retval) + return -EFAULT; + + /* DENC */ + config.denc_format.cvbs_video_format = AV8100_CVBS_625; + config.denc_format.standard_selection = AV8100_PAL_BDGHI; + config.denc_format.enable = 0; + config.denc_format.macrovision_enable = 0; + config.denc_format.internal_generator = 0; + retval = av8100_conf_prep(AV8100_COMMAND_DENC, &config); + if (retval) + return -EFAULT; + + /* Video output */ + config.video_output_format.video_output_cea_vesa = + AV8100_CEA4_1280X720P_60HZ; + + retval = av8100_conf_prep( + AV8100_COMMAND_VIDEO_OUTPUT_FORMAT, &config); + if (retval) + return -EFAULT; + + /* Video input */ + av8100_config_video_output_dep( + config.video_output_format.video_output_cea_vesa); + + /* Pattern generator */ + config.pattern_generator_format.pattern_audio_mode = + AV8100_PATTERN_AUDIO_OFF; + config.pattern_generator_format.pattern_type = + AV8100_PATTERN_GENERATOR; + config.pattern_generator_format.pattern_video_format = + AV8100_PATTERN_720P; + retval = av8100_conf_prep(AV8100_COMMAND_PATTERNGENERATOR, + &config); + if (retval) + return -EFAULT; + + /* Audio input */ + config.audio_input_format.audio_input_if_format = + AV8100_AUDIO_I2SDELAYED_MODE; + config.audio_input_format.i2s_input_nb = 1; + config.audio_input_format.sample_audio_freq = AV8100_AUDIO_FREQ_48KHZ; + config.audio_input_format.audio_word_lg = AV8100_AUDIO_16BITS; + config.audio_input_format.audio_format = AV8100_AUDIO_LPCM_MODE; + config.audio_input_format.audio_if_mode = AV8100_AUDIO_MASTER; + config.audio_input_format.audio_mute = AV8100_AUDIO_MUTE_DISABLE; + retval = av8100_conf_prep( + AV8100_COMMAND_AUDIO_INPUT_FORMAT, &config); + if (retval) + return -EFAULT; + + /* HDMI mode */ + config.hdmi_format.hdmi_mode = AV8100_HDMI_ON; + config.hdmi_format.hdmi_format = AV8100_HDMI; + config.hdmi_format.dvi_format = AV8100_DVI_CTRL_CTL0; + retval = av8100_conf_prep(AV8100_COMMAND_HDMI, &config); + if (retval) + return -EFAULT; + + /* EDID section readback */ + config.edid_section_readback_format.address = 0xA0; + config.edid_section_readback_format.block_number = 0; + retval = av8100_conf_prep( + AV8100_COMMAND_EDID_SECTION_READBACK, &config); + if (retval) + return -EFAULT; + + return 0; +} + +static int av8100_params_init(struct av8100_device *adev) +{ + dev_dbg(adev->dev, "%s\n", __func__); + + memset(&adev->params, 0, sizeof(struct av8100_params)); + + adev->params.denc_off_time = AV8100_DENC_OFF_TIME; + adev->params.hdmi_off_time = AV8100_HDMI_OFF_TIME; + adev->params.on_time = AV8100_ON_TIME; + + adev->params.hpdm = AV8100_STANDBY_INTERRUPT_MASK_HPDM_HIGH; + adev->params.cpdm = AV8100_STANDBY_INTERRUPT_MASK_CPDM_HIGH; + adev->params.hdcpm = AV8100_GENERAL_INTERRUPT_MASK_HDCPM_HIGH; + adev->params.cecm = AV8100_GENERAL_INTERRUPT_MASK_CECM_HIGH; + adev->params.uovbm = AV8100_GENERAL_INTERRUPT_MASK_UOVBM_HIGH; + + return 0; +} + +static void clr_plug_status(struct av8100_device *adev, + enum av8100_plugin_status status) +{ + adev->status.av8100_plugin_status &= ~status; + + switch (status) { + case AV8100_HDMI_PLUGIN: + switch (adev->params.plug_state) { + case AV8100_UNPLUGGED: + case AV8100_PLUGGED_STARTUP: + default: + break; + + case AV8100_PLUGGED: + adev->params.plug_state = + AV8100_UNPLUGGED; + dev_dbg(adev->dev, "plug_state:0\n"); + + if (adev->params.hdmi_ev_cb) + adev->params.hdmi_ev_cb( + AV8100_HDMI_EVENT_HDMI_PLUGOUT); + break; + } + break; + + case AV8100_CVBS_PLUGIN: + /* TODO */ + break; + + default: + break; + } +} + +static void set_plug_status(struct av8100_device *adev, + enum av8100_plugin_status status) +{ + adev->status.av8100_plugin_status |= status; + + switch (status) { + case AV8100_HDMI_PLUGIN: + switch (adev->params.plug_state) { + case AV8100_UNPLUGGED: + adev->params.plug_state = + AV8100_PLUGGED_STARTUP; + + dev_dbg(adev->dev, "plug_state:1\n"); + + /* + * Mask interrupts to avoid plug detect during + * startup + * */ + adev->params.hpdm = + AV8100_STANDBY_INTERRUPT_MASK_HPDM_LOW; + if (av8100_reg_stby_int_mask_w( + adev->params.hpdm, + adev->params.cpdm, + AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_INPUT, + AV8100_STANDBY_INTERRUPT_MASK_IPOL_LOW)) { + dev_dbg(adev->dev, + "av8100_reg_stby_int_mask_w fail\n"); + } + + /* Set plug startup timer */ + init_timer(&adev->timer); + adev->timer.expires = jiffies + + AV8100_PLUGSTARTUP_TIME; + adev->timer.function = + av8100_plugtimer_int; + adev->timer.data = 0; + adev->timer.data = adev_to_devnr(adev); + mod_timer(&adev->timer, adev->timer.expires); + + if (adev->params.hdmi_ev_cb) + adev->params.hdmi_ev_cb( + AV8100_HDMI_EVENT_HDMI_PLUGIN); + break; + + case AV8100_PLUGGED_STARTUP: + case AV8100_PLUGGED: + default: + break; + } + break; + + case AV8100_CVBS_PLUGIN: + /* TODO */ + break; + + default: + break; + } +} + +static void cec_rx(struct av8100_device *adev) +{ + if (adev->params.hdmi_ev_cb) + adev->params.hdmi_ev_cb(AV8100_HDMI_EVENT_CEC); +} + +static void cec_tx(struct av8100_device *adev) +{ + if (adev->params.hdmi_ev_cb) + adev->params.hdmi_ev_cb(AV8100_HDMI_EVENT_CECTX); +} + +static void cec_txerr(struct av8100_device *adev) +{ + if (adev->params.hdmi_ev_cb) + adev->params.hdmi_ev_cb(AV8100_HDMI_EVENT_CECTXERR); +} + +static void hdcp_changed(struct av8100_device *adev) +{ + if (adev->params.hdmi_ev_cb) + adev->params.hdmi_ev_cb(AV8100_HDMI_EVENT_HDCP); +} + +static void av8100_set_state(struct av8100_device *adev, + enum av8100_operating_mode state) +{ + adev->status.av8100_state = state; + + if (state <= AV8100_OPMODE_STANDBY) { + clr_plug_status(adev, AV8100_HDMI_PLUGIN); + clr_plug_status(adev, AV8100_CVBS_PLUGIN); + adev->status.hdmi_on = false; + } +} + +/** + * write_single_byte() - Write a single byte to av8100 + * through i2c interface. + * @client: i2c client structure + * @reg: register offset + * @data: data byte to be written + * + * This funtion uses smbus byte write API to write a single byte to av8100 + **/ +static int write_single_byte(struct i2c_client *client, u8 reg, + u8 data) +{ + int ret; + struct device *dev = &client->dev; + + ret = i2c_smbus_write_byte_data(client, reg, data); + if (ret < 0) + dev_dbg(dev, "i2c smbus write byte failed\n"); + + return ret; +} + +/** + * read_single_byte() - read single byte from av8100 + * through i2c interface + * @client: i2c client structure + * @reg: register offset + * @val: register value + * + * This funtion uses smbus read block API to read single byte from the reg + * offset. + **/ +static int read_single_byte(struct i2c_client *client, u8 reg, u8 *val) +{ + int value; + struct device *dev = &client->dev; + + value = i2c_smbus_read_byte_data(client, reg); + if (value < 0) { + dev_dbg(dev, "i2c smbus read byte failed,read data = %x " + "from offset:%x\n" , value, reg); + return -EFAULT; + } + + *val = (u8) value; + return 0; +} + +/** + * write_multi_byte() - Write a multiple bytes to av8100 through + * i2c interface. + * @client: i2c client structure + * @buf: buffer to be written + * @nbytes: nunmber of bytes to be written + * + * This funtion uses smbus block write API's to write n number of bytes to the + * av8100 + **/ +static int write_multi_byte(struct i2c_client *client, u8 reg, + u8 *buf, u8 nbytes) +{ + int ret; + struct device *dev = &client->dev; + + ret = i2c_smbus_write_i2c_block_data(client, reg, nbytes, buf); + if (ret < 0) + dev_dbg(dev, "i2c smbus write multi byte error\n"); + + return ret; +} + +static int configuration_video_input_get(struct av8100_device *adev, + char *buffer, unsigned int *length) +{ + buffer[0] = adev->config.hdmi_video_input_cmd.dsi_input_mode; + buffer[1] = adev->config.hdmi_video_input_cmd.input_pixel_format; + buffer[2] = REG_16_8_MSB(adev->config.hdmi_video_input_cmd. + total_horizontal_pixel); + buffer[3] = REG_16_8_LSB(adev->config.hdmi_video_input_cmd. + total_horizontal_pixel); + buffer[4] = REG_16_8_MSB(adev->config.hdmi_video_input_cmd. + total_horizontal_active_pixel); + buffer[5] = REG_16_8_LSB(adev->config.hdmi_video_input_cmd. + total_horizontal_active_pixel); + buffer[6] = REG_16_8_MSB(adev->config.hdmi_video_input_cmd. + total_vertical_lines); + buffer[7] = REG_16_8_LSB(adev->config.hdmi_video_input_cmd. + total_vertical_lines); + buffer[8] = REG_16_8_MSB(adev->config.hdmi_video_input_cmd. + total_vertical_active_lines); + buffer[9] = REG_16_8_LSB(adev->config.hdmi_video_input_cmd. + total_vertical_active_lines); + buffer[10] = adev->config.hdmi_video_input_cmd.video_mode; + buffer[11] = adev->config.hdmi_video_input_cmd.nb_data_lane; + buffer[12] = adev->config.hdmi_video_input_cmd. + nb_virtual_ch_command_mode; + buffer[13] = adev->config.hdmi_video_input_cmd. + nb_virtual_ch_video_mode; + buffer[14] = REG_16_8_MSB(adev->config.hdmi_video_input_cmd. + TE_line_nb); + buffer[15] = REG_16_8_LSB(adev->config.hdmi_video_input_cmd. + TE_line_nb); + buffer[16] = adev->config.hdmi_video_input_cmd.TE_config; + buffer[17] = REG_32_8_MSB(adev->config.hdmi_video_input_cmd. + master_clock_freq); + buffer[18] = REG_32_8_MMSB(adev->config.hdmi_video_input_cmd. + master_clock_freq); + buffer[19] = REG_32_8_MLSB(adev->config.hdmi_video_input_cmd. + master_clock_freq); + buffer[20] = REG_32_8_LSB(adev->config.hdmi_video_input_cmd. + master_clock_freq); + buffer[21] = adev->config.hdmi_video_input_cmd.ui_x4; + + *length = AV8100_COMMAND_VIDEO_INPUT_FORMAT_SIZE - 1; + return 0; + +} + +static int configuration_audio_input_get(struct av8100_device *adev, + char *buffer, unsigned int *length) +{ + buffer[0] = adev->config.hdmi_audio_input_cmd.audio_input_if_format; + buffer[1] = adev->config.hdmi_audio_input_cmd.i2s_input_nb; + buffer[2] = adev->config.hdmi_audio_input_cmd.sample_audio_freq; + buffer[3] = adev->config.hdmi_audio_input_cmd.audio_word_lg; + buffer[4] = adev->config.hdmi_audio_input_cmd.audio_format; + buffer[5] = adev->config.hdmi_audio_input_cmd.audio_if_mode; + buffer[6] = adev->config.hdmi_audio_input_cmd.audio_mute; + + *length = AV8100_COMMAND_AUDIO_INPUT_FORMAT_SIZE - 1; + return 0; +} + +static int configuration_video_output_get(struct av8100_device *adev, + char *buffer, unsigned int *length) +{ + buffer[0] = adev->config.hdmi_video_output_cmd. + video_output_cea_vesa; + + if (buffer[0] == AV8100_CUSTOM) { + buffer[1] = adev->config.hdmi_video_output_cmd. + vsync_polarity; + buffer[2] = adev->config.hdmi_video_output_cmd. + hsync_polarity; + buffer[3] = REG_16_8_MSB(adev->config. + hdmi_video_output_cmd.total_horizontal_pixel); + buffer[4] = REG_16_8_LSB(adev->config. + hdmi_video_output_cmd.total_horizontal_pixel); + buffer[5] = REG_16_8_MSB(adev->config. + hdmi_video_output_cmd.total_horizontal_active_pixel); + buffer[6] = REG_16_8_LSB(adev->config. + hdmi_video_output_cmd.total_horizontal_active_pixel); + buffer[7] = REG_16_8_MSB(adev->config. + hdmi_video_output_cmd.total_vertical_in_half_lines); + buffer[8] = REG_16_8_LSB(adev->config. + hdmi_video_output_cmd.total_vertical_in_half_lines); + buffer[9] = REG_16_8_MSB(adev->config. + hdmi_video_output_cmd. + total_vertical_active_in_half_lines); + buffer[10] = REG_16_8_LSB(adev->config. + hdmi_video_output_cmd. + total_vertical_active_in_half_lines); + buffer[11] = REG_16_8_MSB(adev->config. + hdmi_video_output_cmd.hsync_start_in_pixel); + buffer[12] = REG_16_8_LSB(adev->config. + hdmi_video_output_cmd.hsync_start_in_pixel); + buffer[13] = REG_16_8_MSB(adev->config. + hdmi_video_output_cmd.hsync_length_in_pixel); + buffer[14] = REG_16_8_LSB(adev->config. + hdmi_video_output_cmd.hsync_length_in_pixel); + buffer[15] = REG_16_8_MSB(adev->config. + hdmi_video_output_cmd.vsync_start_in_half_line); + buffer[16] = REG_16_8_LSB(adev->config. + hdmi_video_output_cmd.vsync_start_in_half_line); + buffer[17] = REG_16_8_MSB(adev->config. + hdmi_video_output_cmd.vsync_length_in_half_line); + buffer[18] = REG_16_8_LSB(adev->config. + hdmi_video_output_cmd.vsync_length_in_half_line); + buffer[19] = REG_16_8_MSB(adev->config. + hdmi_video_output_cmd.hor_video_start_pixel); + buffer[20] = REG_16_8_LSB(adev->config. + hdmi_video_output_cmd.hor_video_start_pixel); + buffer[21] = REG_16_8_MSB(adev->config. + hdmi_video_output_cmd.vert_video_start_pixel); + buffer[22] = REG_16_8_LSB(adev->config. + hdmi_video_output_cmd.vert_video_start_pixel); + buffer[23] = adev->config.hdmi_video_output_cmd.video_type; + buffer[24] = adev->config.hdmi_video_output_cmd.pixel_repeat; + buffer[25] = REG_32_8_MSB(adev->config. + hdmi_video_output_cmd.pixel_clock_freq_Hz); + buffer[26] = REG_32_8_MMSB(adev->config. + hdmi_video_output_cmd.pixel_clock_freq_Hz); + buffer[27] = REG_32_8_MLSB(adev->config. + hdmi_video_output_cmd.pixel_clock_freq_Hz); + buffer[28] = REG_32_8_LSB(adev->config. + hdmi_video_output_cmd.pixel_clock_freq_Hz); + + *length = AV8100_COMMAND_VIDEO_OUTPUT_FORMAT_SIZE - 1; + } else { + *length = 1; + } + + return 0; +} + +static int configuration_video_scaling_get(struct av8100_device *adev, + char *buffer, unsigned int *length) +{ + buffer[0] = REG_16_8_MSB(adev->config.hdmi_video_scaling_cmd. + h_start_in_pixel); + buffer[1] = REG_16_8_LSB(adev->config.hdmi_video_scaling_cmd. + h_start_in_pixel); + buffer[2] = REG_16_8_MSB(adev->config.hdmi_video_scaling_cmd. + h_stop_in_pixel); + buffer[3] = REG_16_8_LSB(adev->config.hdmi_video_scaling_cmd. + h_stop_in_pixel); + buffer[4] = REG_16_8_MSB(adev->config.hdmi_video_scaling_cmd. + v_start_in_line); + buffer[5] = REG_16_8_LSB(adev->config.hdmi_video_scaling_cmd. + v_start_in_line); + buffer[6] = REG_16_8_MSB(adev->config.hdmi_video_scaling_cmd. + v_stop_in_line); + buffer[7] = REG_16_8_LSB(adev->config.hdmi_video_scaling_cmd. + v_stop_in_line); + buffer[8] = REG_16_8_MSB(adev->config.hdmi_video_scaling_cmd. + h_start_out_pixel); + buffer[9] = REG_16_8_LSB(adev->config.hdmi_video_scaling_cmd + .h_start_out_pixel); + buffer[10] = REG_16_8_MSB(adev->config.hdmi_video_scaling_cmd. + h_stop_out_pixel); + buffer[11] = REG_16_8_LSB(adev->config.hdmi_video_scaling_cmd. + h_stop_out_pixel); + buffer[12] = REG_16_8_MSB(adev->config.hdmi_video_scaling_cmd. + v_start_out_line); + buffer[13] = REG_16_8_LSB(adev->config.hdmi_video_scaling_cmd. + v_start_out_line); + buffer[14] = REG_16_8_MSB(adev->config.hdmi_video_scaling_cmd. + v_stop_out_line); + buffer[15] = REG_16_8_LSB(adev->config.hdmi_video_scaling_cmd. + v_stop_out_line); + + *length = AV8100_COMMAND_VIDEO_SCALING_FORMAT_SIZE - 1; + return 0; +} + +static int configuration_colorspace_conversion_get(struct av8100_device *adev, + char *buffer, unsigned int *length) +{ + const struct color_conversion_cmd *hdmi_color_space_conversion_cmd; + + hdmi_color_space_conversion_cmd = + get_color_transform_cmd(adev, adev->config.color_transform); + + buffer[0] = REG_12_8_MSB(hdmi_color_space_conversion_cmd->c0); + buffer[1] = REG_16_8_LSB(hdmi_color_space_conversion_cmd->c0); + buffer[2] = REG_12_8_MSB(hdmi_color_space_conversion_cmd->c1); + buffer[3] = REG_16_8_LSB(hdmi_color_space_conversion_cmd->c1); + buffer[4] = REG_12_8_MSB(hdmi_color_space_conversion_cmd->c2); + buffer[5] = REG_16_8_LSB(hdmi_color_space_conversion_cmd->c2); + buffer[6] = REG_12_8_MSB(hdmi_color_space_conversion_cmd->c3); + buffer[7] = REG_16_8_LSB(hdmi_color_space_conversion_cmd->c3); + buffer[8] = REG_12_8_MSB(hdmi_color_space_conversion_cmd->c4); + buffer[9] = REG_16_8_LSB(hdmi_color_space_conversion_cmd->c4); + buffer[10] = REG_12_8_MSB(hdmi_color_space_conversion_cmd->c5); + buffer[11] = REG_16_8_LSB(hdmi_color_space_conversion_cmd->c5); + buffer[12] = REG_12_8_MSB(hdmi_color_space_conversion_cmd->c6); + buffer[13] = REG_16_8_LSB(hdmi_color_space_conversion_cmd->c6); + buffer[14] = REG_12_8_MSB(hdmi_color_space_conversion_cmd->c7); + buffer[15] = REG_16_8_LSB(hdmi_color_space_conversion_cmd->c7); + buffer[16] = REG_12_8_MSB(hdmi_color_space_conversion_cmd->c8); + buffer[17] = REG_16_8_LSB(hdmi_color_space_conversion_cmd->c8); + buffer[18] = REG_10_8_MSB(hdmi_color_space_conversion_cmd->aoffset); + buffer[19] = REG_16_8_LSB(hdmi_color_space_conversion_cmd->aoffset); + buffer[20] = REG_10_8_MSB(hdmi_color_space_conversion_cmd->boffset); + buffer[21] = REG_16_8_LSB(hdmi_color_space_conversion_cmd->boffset); + buffer[22] = REG_10_8_MSB(hdmi_color_space_conversion_cmd->coffset); + buffer[23] = REG_16_8_LSB(hdmi_color_space_conversion_cmd->coffset); + buffer[24] = hdmi_color_space_conversion_cmd->lmax; + buffer[25] = hdmi_color_space_conversion_cmd->lmin; + buffer[26] = hdmi_color_space_conversion_cmd->cmax; + buffer[27] = hdmi_color_space_conversion_cmd->cmin; + + *length = AV8100_COMMAND_COLORSPACECONVERSION_SIZE - 1; + return 0; +} + +static int configuration_cec_message_write_get(struct av8100_device *adev, + char *buffer, unsigned int *length) +{ + buffer[0] = adev->config.hdmi_cec_message_write_cmd.buffer_length; + memcpy(&buffer[1], adev->config.hdmi_cec_message_write_cmd.buffer, + adev->config.hdmi_cec_message_write_cmd.buffer_length); + + *length = adev->config.hdmi_cec_message_write_cmd.buffer_length + 1; + + return 0; +} + +static int configuration_cec_message_read_get(char *buffer, + unsigned int *length) +{ + /* No buffer data */ + *length = AV8100_COMMAND_CEC_MESSAGE_READ_BACK_SIZE - 1; + return 0; +} + +static int configuration_denc_get(struct av8100_device *adev, + char *buffer, unsigned int *length) +{ + buffer[0] = adev->config.hdmi_denc_cmd.cvbs_video_format; + buffer[1] = adev->config.hdmi_denc_cmd.standard_selection; + buffer[2] = adev->config.hdmi_denc_cmd.enable; + buffer[3] = adev->config.hdmi_denc_cmd.macrovision_enable; + buffer[4] = adev->config.hdmi_denc_cmd.internal_generator; + + *length = AV8100_COMMAND_DENC_SIZE - 1; + return 0; +} + +static int configuration_hdmi_get(struct av8100_device *adev, + char *buffer, unsigned int *length) +{ + buffer[0] = adev->config.hdmi_cmd.hdmi_mode; + buffer[1] = adev->config.hdmi_cmd.hdmi_format; + buffer[2] = adev->config.hdmi_cmd.dvi_format; + + *length = AV8100_COMMAND_HDMI_SIZE - 1; + return 0; +} + +static int configuration_hdcp_sendkey_get(struct av8100_device *adev, + char *buffer, unsigned int *length) +{ + buffer[0] = adev->config.hdmi_hdcp_send_key_cmd.key_number; + memcpy(&buffer[1], adev->config.hdmi_hdcp_send_key_cmd.data, + adev->config.hdmi_hdcp_send_key_cmd.data_len); + + *length = adev->config.hdmi_hdcp_send_key_cmd.data_len + 1; + return 0; +} + +static int configuration_hdcp_management_get(struct av8100_device *adev, + char *buffer, unsigned int *length) +{ + buffer[0] = adev->config.hdmi_hdcp_management_format_cmd.req_type; + buffer[1] = adev->config.hdmi_hdcp_management_format_cmd.encr_use; + + *length = AV8100_COMMAND_HDCP_MANAGEMENT_SIZE - 1; + return 0; +} + +static int configuration_infoframe_get(struct av8100_device *adev, + char *buffer, unsigned int *length) +{ + buffer[0] = adev->config.hdmi_infoframes_cmd.type; + buffer[1] = adev->config.hdmi_infoframes_cmd.version; + buffer[2] = adev->config.hdmi_infoframes_cmd.length; + buffer[3] = adev->config.hdmi_infoframes_cmd.crc; + memcpy(&buffer[4], adev->config.hdmi_infoframes_cmd.data, + HDMI_INFOFRAME_DATA_SIZE); + + *length = adev->config.hdmi_infoframes_cmd.length + 4; + return 0; +} + +static int av8100_edid_section_readback_get(struct av8100_device *adev, + char *buffer, unsigned int *length) +{ + buffer[0] = adev->config.hdmi_edid_section_readback_cmd.address; + buffer[1] = adev->config.hdmi_edid_section_readback_cmd. + block_number; + + *length = AV8100_COMMAND_EDID_SECTION_READBACK_SIZE - 1; + return 0; +} + +static int configuration_pattern_generator_get(struct av8100_device *adev, + char *buffer, unsigned int *length) +{ + buffer[0] = adev->config.hdmi_pattern_generator_cmd.pattern_type; + buffer[1] = adev->config.hdmi_pattern_generator_cmd. + pattern_video_format; + buffer[2] = adev->config.hdmi_pattern_generator_cmd. + pattern_audio_mode; + + *length = AV8100_COMMAND_PATTERNGENERATOR_SIZE - 1; + return 0; +} + +static int configuration_fuse_aes_key_get(struct av8100_device *adev, + char *buffer, unsigned int *length) +{ + buffer[0] = adev->config.hdmi_fuse_aes_key_cmd.fuse_operation; + if (adev->config.hdmi_fuse_aes_key_cmd.fuse_operation) { + /* Write key command */ + memcpy(&buffer[1], adev->config.hdmi_fuse_aes_key_cmd.key, + HDMI_FUSE_AES_KEY_SIZE); + + *length = AV8100_COMMAND_FUSE_AES_KEY_SIZE - 1; + } else { + /* Check key command */ + *length = AV8100_COMMAND_FUSE_AES_CHK_SIZE - 1; + } + return 0; +} + +static int get_command_return_first(struct i2c_client *i2c, + enum av8100_command_type command_type) { + int retval = 0; + char val; + struct device *dev = &i2c->dev; + + retval = read_single_byte(i2c, AV8100_COMMAND_OFFSET, &val); + if (retval) { + dev_dbg(dev, "%s 1st ret failed\n", __func__); + return retval; + } + + if (val != (0x80 | command_type)) { + dev_dbg(dev, "%s 1st ret wrong:%x\n", __func__, val); + return -EFAULT; + } + + return 0; +} + +static int get_command_return_data(struct i2c_client *i2c, + enum av8100_command_type command_type, + u8 *command_buffer, + u8 *buffer_length, + u8 *buffer) +{ + int retval = 0; + char val; + int index = 0; + struct device *dev = &i2c->dev; + + if (buffer_length) + *buffer_length = 0; + + switch (command_type) { + case AV8100_COMMAND_VIDEO_INPUT_FORMAT: + case AV8100_COMMAND_AUDIO_INPUT_FORMAT: + case AV8100_COMMAND_VIDEO_OUTPUT_FORMAT: + case AV8100_COMMAND_VIDEO_SCALING_FORMAT: + case AV8100_COMMAND_COLORSPACECONVERSION: + case AV8100_COMMAND_CEC_MESSAGE_WRITE: + case AV8100_COMMAND_DENC: + case AV8100_COMMAND_HDMI: + case AV8100_COMMAND_INFOFRAMES: + case AV8100_COMMAND_PATTERNGENERATOR: + /* Get the second return byte */ + retval = read_single_byte(i2c, + AV8100_2ND_RET_BYTE_OFFSET, &val); + if (retval) + goto get_command_return_data_fail2r; + + if (val) { + retval = -EFAULT; + goto get_command_return_data_fail2v; + } + break; + + case AV8100_COMMAND_CEC_MESSAGE_READ_BACK: + if ((buffer == NULL) || (buffer_length == NULL)) { + retval = -EINVAL; + goto get_command_return_data_fail; + } + + /* Get the return buffer length */ + retval = read_single_byte(i2c, AV8100_CEC_ADDR_OFFSET, &val); + if (retval) + goto get_command_return_data_fail; + + dev_dbg(dev, "cec buflen:%d\n", val); + *buffer_length = val; + + if (*buffer_length > + HDMI_CEC_READ_MAXSIZE) { + dev_dbg(dev, "CEC size too large %d\n", + *buffer_length); + *buffer_length = HDMI_CEC_READ_MAXSIZE; + } + + dev_dbg(dev, "return data: "); + + /* Get the return buffer */ + for (index = 0; index < *buffer_length; ++index) { + retval = read_single_byte(i2c, + AV8100_CEC_RET_BUF_OFFSET + index, &val); + if (retval) { + *buffer_length = 0; + goto get_command_return_data_fail; + } else { + *(buffer + index) = val; + dev_dbg(dev, "%02x ", *(buffer + index)); + } + } + + dev_dbg(dev, "\n"); + break; + + case AV8100_COMMAND_HDCP_MANAGEMENT: + { + u8 nrdev; + u8 devcnt; + int cnt; + + /* Get the second return byte */ + retval = read_single_byte(i2c, + AV8100_2ND_RET_BYTE_OFFSET, &val); + if (retval) { + goto get_command_return_data_fail2r; + } else { + /* Check the second return byte */ + if (val) + goto get_command_return_data_fail2v; + } + + if ((buffer == NULL) || (buffer_length == NULL)) + /* Ignore return data */ + break; + + dev_dbg(dev, "req_type:%02x ", command_buffer[0]); + + /* Check if revoc list data is requested */ + if (command_buffer[0] != + HDMI_REQUEST_FOR_REVOCATION_LIST_INPUT) { + *buffer_length = 0; + break; + } + + dev_dbg(dev, "return data: "); + + /* Get the return buffer */ + for (cnt = 0; cnt < HDMI_HDCP_MGMT_BKSV_SIZE; cnt++) { + retval = read_single_byte(i2c, + AV8100_HDCP_RET_BUF_OFFSET + index, &val); + if (retval) { + *buffer_length = 0; + goto get_command_return_data_fail; + } else { + *(buffer + index) = val; + dev_dbg(dev, "%02x ", *(buffer + index)); + } + index++; + } + + /* Get Device count */ + retval = read_single_byte(i2c, + AV8100_HDCP_RET_BUF_OFFSET + index, &nrdev); + if (retval) { + *buffer_length = 0; + goto get_command_return_data_fail; + } else { + *(buffer + index) = nrdev; + dev_dbg(dev, "%02x ", *(buffer + index)); + } + index++; + + /* Determine number of devices */ + nrdev &= HDMI_HDCP_MGMT_DEVICE_MASK; + if (nrdev > HDMI_HDCP_MGMT_MAX_DEVICES_SIZE) + nrdev = HDMI_HDCP_MGMT_MAX_DEVICES_SIZE; + + /* Get Bksv for each connected equipment */ + for (devcnt = 0; devcnt < nrdev; devcnt++) + for (cnt = 0; cnt < HDMI_HDCP_MGMT_BKSV_SIZE; cnt++) { + retval = read_single_byte(i2c, + AV8100_HDCP_RET_BUF_OFFSET + index, + &val); + if (retval) { + *buffer_length = 0; + goto get_command_return_data_fail; + } else { + *(buffer + index) = val; + dev_dbg(dev, "%02x ", + *(buffer + index)); + } + index++; + } + + if (nrdev == 0) + goto hdcp_management_end; + + /* Get SHA signature */ + for (cnt = 0; cnt < HDMI_HDCP_MGMT_SHA_SIZE - 1; cnt++) { + retval = read_single_byte(i2c, + AV8100_HDCP_RET_BUF_OFFSET + index, &val); + if (retval) { + *buffer_length = 0; + goto get_command_return_data_fail; + } else { + *(buffer + index) = val; + dev_dbg(dev, "%02x ", *(buffer + index)); + } + index++; + } + +hdcp_management_end: + *buffer_length = index; + + dev_dbg(dev, "\n"); + } + break; + + case AV8100_COMMAND_EDID_SECTION_READBACK: + if ((buffer == NULL) || (buffer_length == NULL)) { + retval = -EINVAL; + goto get_command_return_data_fail; + } + + /* Return buffer length is fixed */ + *buffer_length = HDMI_EDIDREAD_SIZE; + + dev_dbg(dev, "return data: "); + + /* Get the return buffer */ + for (index = 0; index < *buffer_length; ++index) { + retval = read_single_byte(i2c, + AV8100_EDID_RET_BUF_OFFSET + index, &val); + if (retval) { + *buffer_length = 0; + goto get_command_return_data_fail; + } else { + *(buffer + index) = val; + dev_dbg(dev, "%02x ", *(buffer + index)); + } + } + + dev_dbg(dev, "\n"); + break; + + case AV8100_COMMAND_FUSE_AES_KEY: + if ((buffer == NULL) || (buffer_length == NULL)) { + retval = -EINVAL; + goto get_command_return_data_fail; + } + + /* Get the second return byte */ + retval = read_single_byte(i2c, + AV8100_2ND_RET_BYTE_OFFSET, &val); + + if (retval) + goto get_command_return_data_fail2r; + + /* Check the second return byte */ + if (val) { + retval = -EFAULT; + goto get_command_return_data_fail2v; + } + + /* Return buffer length is fixed */ + *buffer_length = HDMI_FUSE_AES_KEY_RET_SIZE; + + /* Get CRC */ + retval = read_single_byte(i2c, + AV8100_FUSE_CRC_OFFSET, &val); + if (retval) + goto get_command_return_data_fail; + + *buffer = val; + dev_dbg(dev, "CRC:%02x ", val); + + /* Get programmed status */ + retval = read_single_byte(i2c, + AV8100_FUSE_PRGD_OFFSET, &val); + if (retval) + goto get_command_return_data_fail; + + *(buffer + 1) = val; + + dev_dbg(dev, "programmed:%02x ", val); + break; + + case AV8100_COMMAND_HDCP_SENDKEY: + if ((command_buffer[0] == HDMI_LOADAES_END_BLK_NR) && + ((buffer == NULL) || (buffer_length == NULL))) { + retval = -EINVAL; + goto get_command_return_data_fail; + } + + /* Get the second return byte */ + retval = read_single_byte(i2c, + AV8100_2ND_RET_BYTE_OFFSET, &val); + if (retval) + goto get_command_return_data_fail2r; + + if (val) { + retval = -EFAULT; + goto get_command_return_data_fail2v; + } + + if (command_buffer[0] == HDMI_LOADAES_END_BLK_NR) { + /* Return CRC32 if last AES block */ + int cnt; + + dev_dbg(dev, "CRC32:"); + for (cnt = 0; cnt < HDMI_CRC32_SIZE; cnt++) { + if (read_single_byte(i2c, + AV8100_CRC32_OFFSET + cnt, &val)) + goto get_command_return_data_fail; + *(buffer + cnt) = val; + dev_dbg(dev, "%02x", val); + } + + *buffer_length = HDMI_CRC32_SIZE; + } + break; + + default: + retval = -EFAULT; + break; + } + + return retval; +get_command_return_data_fail2r: + dev_dbg(dev, "%s Reading 2nd return byte failed\n", __func__); + return retval; +get_command_return_data_fail2v: + dev_dbg(dev, "%s 2nd return byte is wrong:%x\n", __func__, val); + return retval; +get_command_return_data_fail: + dev_dbg(dev, "%s FAIL\n", __func__); + return retval; +} + +static int av8100_powerup1(struct av8100_device *adev) +{ + int retval; + struct av8100_platform_data *pdata = adev->dev->platform_data; + + /* Regulator enable */ + if ((adev->params.regulator_pwr) && + (adev->params.regulator_requested == false)) { + retval = regulator_enable(adev->params.regulator_pwr); + if (retval < 0) { + dev_warn(adev->dev, "%s: regulator_enable failed\n", + __func__); + return retval; + } + dev_dbg(adev->dev, "regulator_enable ok\n"); + adev->params.regulator_requested = true; + } + + /* Reset av8100 */ + gpio_set_value_cansleep(pdata->reset, 1); + + /* Need to wait before proceeding */ + mdelay(AV8100_WAITTIME_1MS); + + av8100_set_state(adev, AV8100_OPMODE_STANDBY); + + if (pdata->alt_powerupseq) { + dev_dbg(adev->dev, "powerup seq alt\n"); + retval = av8100_5V_w(0, 0, AV8100_ON_TIME); + if (retval) { + dev_err(adev->dev, "%s reg_wr err 1\n", __func__); + goto av8100_powerup1_err; + } + + udelay(AV8100_WATTIME_100US); + + retval = av8100_reg_stby_pend_int_w( + AV8100_STANDBY_PENDING_INTERRUPT_HPDI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_CPDI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_ONI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_BPDIG_HIGH); + if (retval) { + dev_err(adev->dev, "%s reg_wr err 2\n", __func__); + goto av8100_powerup1_err; + } + + udelay(AV8100_WATTIME_100US); + + retval = av8100_reg_stby_w(AV8100_STANDBY_CPD_LOW, + AV8100_STANDBY_STBY_HIGH, pdata->mclk_freq); + if (retval) { + dev_err(adev->dev, "%s reg_wr err 3\n", __func__); + goto av8100_powerup1_err; + } + + mdelay(AV8100_WAITTIME_1MS); + + retval = av8100_reg_stby_w(AV8100_STANDBY_CPD_LOW, + AV8100_STANDBY_STBY_LOW, pdata->mclk_freq); + if (retval) { + dev_err(adev->dev, "%s reg_wr err 4\n", __func__); + goto av8100_powerup1_err; + } + + mdelay(AV8100_WAITTIME_1MS); + + retval = av8100_reg_stby_pend_int_w( + AV8100_STANDBY_PENDING_INTERRUPT_HPDI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_CPDI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_ONI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_BPDIG_LOW); + if (retval) { + dev_err(adev->dev, "%s reg_wr err 5\n", __func__); + goto av8100_powerup1_err; + } + + mdelay(AV8100_WAITTIME_1MS); + } + + retval = request_irq(pdata->irq, av8100_intr_handler, + IRQF_TRIGGER_RISING, "av8100", adev); + if (retval == 0) + adev->params.irq_requested = true; + else + dev_err(adev->dev, "request_irq %d failed %d\n", + pdata->irq, retval); + + return retval; + +av8100_powerup1_err: + av8100_powerdown(); + return -EFAULT; +} + +static int av8100_powerup2(struct av8100_device *adev) +{ + int retval; + + /* ON time & OFF time on 5v HDMI plug detect */ + retval = av8100_5V_w(adev->params.denc_off_time, + adev->params.hdmi_off_time, + adev->params.on_time); + if (retval) { + dev_err(adev->dev, + "Failed to write the value to av8100 register\n"); + return retval; + } + + mdelay(AV8100_WAITTIME_1MS); + + av8100_set_state(adev, AV8100_OPMODE_SCAN); + + return 0; +} + +static int register_read_internal(u8 offset, u8 *value) +{ + int retval = 0; + struct i2c_client *i2c; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EFAULT; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + i2c = adev->config.client; + + /* Read from register */ + retval = read_single_byte(i2c, offset, value); + if (retval) { + dev_dbg(adev->dev, + "Failed to read the value from av8100 register\n"); + return -EFAULT; + } + + return retval; +} + +static int register_write_internal(u8 offset, u8 value) +{ + int retval; + struct i2c_client *i2c; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EFAULT; + + i2c = adev->config.client; + + /* Write to register */ + retval = write_single_byte(i2c, offset, value); + if (retval) { + dev_dbg(adev->dev, + "Failed to write the value to av8100 register\n"); + return -EFAULT; + } + + return 0; +} + +int av8100_powerscan(void) +{ + int retval; + struct av8100_device *adev; + struct av8100_platform_data *pdata; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EFAULT; + + pdata = adev->dev->platform_data; + + dev_dbg(adev->dev, "%s\n", __func__); + + if (av8100_status_get().av8100_state > AV8100_OPMODE_SCAN) { + dev_dbg(adev->dev, "set to scan mode\n"); + + av8100_disable_interrupt(); + + /* Stby mode */ + retval = av8100_reg_stby_w(AV8100_STANDBY_CPD_LOW, + AV8100_STANDBY_STBY_LOW, pdata->mclk_freq); + if (retval) { + dev_err(adev->dev, + "Failed to write to av8100 register\n"); + return retval; + } + + /* Remove APE OPP requirement */ + if (adev->params.opp_requested) { + prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, + (char *)adev->miscdev.name); + prcmu_qos_remove_requirement(PRCMU_QOS_DDR_OPP, + (char *)adev->miscdev.name); + adev->params.opp_requested = false; + } + + /* Clock disable */ + if (adev->params.inputclk && + adev->params.inputclk_requested) { + clk_disable(adev->params.inputclk); + adev->params.inputclk_requested = false; + } + + mdelay(AV8100_WAITTIME_1MS); + + av8100_enable_interrupt(); + + av8100_set_state(adev, AV8100_OPMODE_SCAN); + } + + return 0; +} +EXPORT_SYMBOL(av8100_powerscan); + +int av8100_powerup(void) +{ + int ret = 0; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EFAULT; + + if (av8100_status_get().av8100_state == AV8100_OPMODE_UNDEFINED) + return -EINVAL; + + if (av8100_status_get().av8100_state < AV8100_OPMODE_STANDBY) { + ret = av8100_powerup1(adev); + if (ret) { + dev_err(adev->dev, "av8100_powerup1 fail\n"); + return -EFAULT; + } + } + + if (av8100_status_get().av8100_state < AV8100_OPMODE_SCAN) + ret = av8100_powerup2(adev); + + av8100_enable_interrupt(); + + return ret; +} +EXPORT_SYMBOL(av8100_powerup); + +int av8100_powerdown(void) +{ + int retval = 0; + struct av8100_device *adev; + struct av8100_platform_data *pdata; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EFAULT; + + pdata = adev->dev->platform_data; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + goto av8100_powerdown_end; + + av8100_disable_interrupt(); + + if (adev->params.irq_requested) + free_irq(pdata->irq, adev); + adev->params.irq_requested = false; + + if (pdata->alt_powerupseq) { + retval = av8100_reg_stby_pend_int_w( + AV8100_STANDBY_PENDING_INTERRUPT_HPDI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_CPDI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_ONI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_BPDIG_HIGH); + + if (retval) + dev_err(adev->dev, "%s reg_wr err\n", __func__); + msleep(AV8100_WAITTIME_50MS); + } + + /* Remove APE OPP requirement */ + if (adev->params.opp_requested) { + prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, + (char *)adev->miscdev.name); + prcmu_qos_remove_requirement(PRCMU_QOS_DDR_OPP, + (char *)adev->miscdev.name); + adev->params.opp_requested = false; + } + + /* Clock disable */ + if (adev->params.inputclk && adev->params.inputclk_requested) { + clk_disable(adev->params.inputclk); + adev->params.inputclk_requested = false; + } + + av8100_set_state(adev, AV8100_OPMODE_SHUTDOWN); + + gpio_set_value_cansleep(pdata->reset, 0); + + /* Regulator disable */ + if ((adev->params.regulator_pwr) && + (adev->params.regulator_requested)) { + dev_dbg(adev->dev, "regulator_disable\n"); + regulator_disable(adev->params.regulator_pwr); + adev->params.regulator_requested = false; + } + + if (pdata->alt_powerupseq) + mdelay(AV8100_WAITTIME_5MS); + +av8100_powerdown_end: + return retval; +} +EXPORT_SYMBOL(av8100_powerdown); + +int av8100_download_firmware(enum interface_type if_type) +{ + int retval; + int temp = 0x0; + int increment = 15; + int index = 0; + int size = 0x0; + char val = 0x0; + char checksum = 0; + int cnt; + int cnt_max; + struct i2c_client *i2c; + u8 uc; + u8 fdl; + u8 hld; + u8 wa; + u8 ra; + struct av8100_platform_data *pdata; + const struct firmware *fw_file; + u8 *fw_buff; + int fw_bytes; + struct av8100_device *adev; + struct av8100_status status; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EINVAL; + + LOCK_AV8100_FWDL; + + status = av8100_status_get(); + if (status.av8100_state <= AV8100_OPMODE_SHUTDOWN) { + retval = -EINVAL; + goto av8100_download_firmware_err2; + } + + if (status.av8100_state >= AV8100_OPMODE_INIT) { + dev_dbg(adev->dev, "FW already ok\n"); + retval = 0; + goto av8100_download_firmware_err2; + } + + av8100_set_state(adev, AV8100_OPMODE_INIT); + + pdata = adev->dev->platform_data; + + /* Request firmware */ + if (request_firmware(&fw_file, + AV8100_FW_FILENAME, + adev->dev)) { + dev_err(adev->dev, "fw request failed\n"); + retval = -EFAULT; + goto av8100_download_firmware_err2; + } + + /* Master clock timing, running */ + retval = av8100_reg_stby_w(AV8100_STANDBY_CPD_LOW, + AV8100_STANDBY_STBY_HIGH, pdata->mclk_freq); + if (retval) { + dev_err(adev->dev, + "Failed to write the value to av8100 register\n"); + goto av8100_download_firmware_err; + } + + mdelay(AV8100_WAITTIME_1MS); + + /* Clock enable */ + if (adev->params.inputclk && + adev->params.inputclk_requested == false) { + if (clk_enable(adev->params.inputclk)) { + dev_err(adev->dev, "inputclk en failed\n"); + retval = -EFAULT; + goto av8100_download_firmware_err; + } + + adev->params.inputclk_requested = true; + } + + /* Request 100% APE OPP */ + if (adev->params.opp_requested == false) { + if (prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, + (char *)adev->miscdev.name, 100)) { + dev_err(adev->dev, "APE OPP 100 failed\n"); + retval = -EFAULT; + goto av8100_download_firmware_err; + } + if (prcmu_qos_add_requirement(PRCMU_QOS_DDR_OPP, + (char *)adev->miscdev.name, 100)) { + dev_err(adev->dev, "DDR OPP 100 failed\n"); + prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, + (char *)adev->miscdev.name); + retval = -EFAULT; + goto av8100_download_firmware_err; + } + + adev->params.opp_requested = true; + } + + msleep(AV8100_WAITTIME_10MS); + + /* Prepare firmware data */ + fw_bytes = fw_file->size; + fw_buff = (u8 *)fw_file->data; + dev_dbg(adev->dev, "fw size:%d\n", fw_bytes); + + i2c = adev->config.client; + + /* Enable firmware download */ + retval = av8100_reg_gen_ctrl_w( + AV8100_GENERAL_CONTROL_FDL_HIGH, + AV8100_GENERAL_CONTROL_HLD_HIGH, + AV8100_GENERAL_CONTROL_WA_LOW, + AV8100_GENERAL_CONTROL_RA_LOW); + if (retval) { + dev_err(adev->dev, + "Failed to write the value to av8100 register\n"); + retval = -EFAULT; + goto av8100_download_firmware_err; + } + + retval = av8100_reg_gen_ctrl_r(&fdl, &hld, &wa, &ra); + if (retval) { + dev_err(adev->dev, + "Failed to read the value from av8100 register\n"); + retval = -EFAULT; + goto av8100_download_firmware_err; + } else { + dev_dbg(adev->dev, "GENERAL_CONTROL_REG register fdl:%d " + "hld:%d wa:%d ra:%d\n", fdl, hld, wa, ra); + } + + LOCK_AV8100_HW; + + temp = fw_bytes % increment; + for (size = 0; size < (fw_bytes-temp); size = size + increment, + index += increment) { + if (if_type == I2C_INTERFACE) { + retval = write_multi_byte(i2c, + AV8100_FIRMWARE_DOWNLOAD_ENTRY, fw_buff + size, + increment); + if (retval) { + dev_dbg(adev->dev, "Failed to download the " + "av8100 firmware\n"); + UNLOCK_AV8100_HW; + retval = -EFAULT; + goto av8100_download_firmware_err; + } + } else if (if_type == DSI_INTERFACE) { + dev_dbg(adev->dev, + "DSI_INTERFACE is currently not supported\n"); + UNLOCK_AV8100_HW; + retval = -EINVAL; + goto av8100_download_firmware_err; + } else { + UNLOCK_AV8100_HW; + retval = -EINVAL; + goto av8100_download_firmware_err; + } + } + + /* Transfer last firmware bytes */ + if (if_type == I2C_INTERFACE) { + retval = write_multi_byte(i2c, + AV8100_FIRMWARE_DOWNLOAD_ENTRY, fw_buff + size, temp); + if (retval) { + dev_dbg(adev->dev, + "Failed to download the av8100 firmware\n"); + UNLOCK_AV8100_HW; + retval = -EFAULT; + goto av8100_download_firmware_err; + } + } else if (if_type == DSI_INTERFACE) { + /* TODO: Add support for DSI firmware download */ + UNLOCK_AV8100_HW; + retval = -EINVAL; + goto av8100_download_firmware_err; + } else { + UNLOCK_AV8100_HW; + retval = -EINVAL; + goto av8100_download_firmware_err; + } + + /* check transfer*/ + for (size = 0; size < fw_bytes; size++) + checksum = checksum ^ fw_buff[size]; + + UNLOCK_AV8100_HW; + + retval = av8100_reg_fw_dl_entry_r(&val); + if (retval) { + dev_dbg(adev->dev, + "Failed to read the value from the av8100 register\n"); + retval = -EFAULT; + goto av8100_download_firmware_err; + } + + dev_dbg(adev->dev, "checksum:%x,val:%x\n", checksum, val); + + if (checksum != val) { + dev_dbg(adev->dev, + ">Fw downloading.... FAIL checksum issue\n"); + dev_dbg(adev->dev, "checksum = %d\n", checksum); + dev_dbg(adev->dev, "checksum read: %d\n", val); + retval = -EFAULT; + goto av8100_download_firmware_err; + } else { + dev_dbg(adev->dev, ">Fw downloading.... success\n"); + } + + /* Set to idle mode */ + av8100_reg_gen_ctrl_w(AV8100_GENERAL_CONTROL_FDL_LOW, + AV8100_GENERAL_CONTROL_HLD_LOW, AV8100_GENERAL_CONTROL_WA_LOW, + AV8100_GENERAL_CONTROL_RA_LOW); + if (retval) { + dev_dbg(adev->dev, + "Failed to write the value to the av8100 register\n"); + retval = -EFAULT; + goto av8100_download_firmware_err; + } + + /* Wait Internal Micro controler ready */ + cnt = 0; + cnt_max = sizeof(waittime_retry) / sizeof(waittime_retry[0]); + retval = av8100_reg_gen_status_r(NULL, NULL, NULL, &uc, + NULL, NULL); + while ((retval == 0) && (uc != 0x1) && (cnt < cnt_max)) { + mdelay(waittime_retry[cnt]); + retval = av8100_reg_gen_status_r(NULL, NULL, NULL, + &uc, NULL, NULL); + cnt++; + } + dev_dbg(adev->dev, "av8100 fwdl cnt:%d\n", cnt); + + if (retval) { + dev_dbg(adev->dev, + "Failed to read the value from the av8100 register\n"); + retval = -EFAULT; + goto av8100_download_firmware_err; + } + + if (uc != 0x1) + dev_dbg(adev->dev, "UC is not ready\n"); + + release_firmware(fw_file); + + if (adev->chip_version != 1) { + char *cut_str; + + /* Get cut version */ + retval = read_single_byte(i2c, AV8100_CUTVER_OFFSET, &val); + if (retval) { + dev_err(adev->dev, "Read cut ver failed\n"); + return retval; + } + + switch (val) { + case 0x00: + cut_str = CUT_STR_0; + break; + case 0x01: + cut_str = CUT_STR_1; + break; + case 0x03: + cut_str = CUT_STR_3; + break; + case 0x30: + cut_str = CUT_STR_30; + break; + default: + cut_str = CUT_STR_UNKNOWN; + break; + } + dev_dbg(adev->dev, "Cut ver %d %s\n", val, cut_str); + } + + av8100_set_state(adev, AV8100_OPMODE_IDLE); + + UNLOCK_AV8100_FWDL; + return 0; + +av8100_download_firmware_err: + release_firmware(fw_file); + + /* Remove APE OPP requirement */ + if (adev->params.opp_requested) { + prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, + (char *)adev->miscdev.name); + prcmu_qos_remove_requirement(PRCMU_QOS_DDR_OPP, + (char *)adev->miscdev.name); + adev->params.opp_requested = false; + } + + /* Clock disable */ + if (adev->params.inputclk && adev->params.inputclk_requested) { + clk_disable(adev->params.inputclk); + adev->params.inputclk_requested = false; + } + +av8100_download_firmware_err2: + UNLOCK_AV8100_FWDL; + return retval; +} +EXPORT_SYMBOL(av8100_download_firmware); + +int av8100_disable_interrupt(void) +{ + int retval; + u8 hpdm = 0; + u8 cpdm = 0; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EINVAL; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + if (!adev->params.ints_enabled) + return 0; + + retval = av8100_reg_stby_pend_int_w( + AV8100_STANDBY_PENDING_INTERRUPT_HPDI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_CPDI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_ONI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_BPDIG_LOW); + if (retval) { + dev_dbg(adev->dev, + "Failed to write the value to av8100 register\n"); + return -EFAULT; + } + + retval = av8100_reg_gen_int_mask_w( + AV8100_GENERAL_INTERRUPT_MASK_EOCM_LOW, + AV8100_GENERAL_INTERRUPT_MASK_VSIM_LOW, + AV8100_GENERAL_INTERRUPT_MASK_VSOM_LOW, + AV8100_GENERAL_INTERRUPT_MASK_CECM_LOW, + AV8100_GENERAL_INTERRUPT_MASK_HDCPM_LOW, + AV8100_GENERAL_INTERRUPT_MASK_UOVBM_LOW, + AV8100_GENERAL_INTERRUPT_MASK_TEM_LOW); + if (retval) { + dev_dbg(adev->dev, + "Failed to write the value to av8100 register\n"); + return -EFAULT; + } + + hpdm = adev->params.hpdm; + cpdm = adev->params.cpdm; + + retval = av8100_reg_stby_int_mask_w( + AV8100_STANDBY_INTERRUPT_MASK_HPDM_LOW, + AV8100_STANDBY_INTERRUPT_MASK_CPDM_LOW, + AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_INPUT, + AV8100_STANDBY_INTERRUPT_MASK_IPOL_LOW); + if (retval) { + dev_dbg(adev->dev, + "Failed to write the value to av8100 register\n"); + return -EFAULT; + } + + adev->params.hpdm = hpdm; + adev->params.cpdm = cpdm; + adev->params.ints_enabled = false; + + return 0; +} +EXPORT_SYMBOL(av8100_disable_interrupt); + +int av8100_enable_interrupt(void) +{ + int retval; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EINVAL; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + if (adev->params.ints_enabled) + return 0; + + retval = av8100_reg_stby_pend_int_w( + AV8100_STANDBY_PENDING_INTERRUPT_HPDI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_CPDI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_ONI_LOW, + AV8100_STANDBY_PENDING_INTERRUPT_BPDIG_LOW); + if (retval) { + dev_dbg(adev->dev, + "Failed to write the value to av8100 register\n"); + return -EFAULT; + } + + retval = av8100_reg_gen_int_mask_w( + AV8100_GENERAL_INTERRUPT_MASK_EOCM_LOW, + AV8100_GENERAL_INTERRUPT_MASK_VSIM_LOW, + AV8100_GENERAL_INTERRUPT_MASK_VSOM_LOW, + adev->params.cecm, + adev->params.hdcpm, + adev->params.uovbm, + AV8100_GENERAL_INTERRUPT_MASK_TEM_LOW); + if (retval) { + dev_dbg(adev->dev, + "Failed to write the value to av8100 register\n"); + return -EFAULT; + } + + retval = av8100_reg_stby_int_mask_w( + adev->params.hpdm, + adev->params.cpdm, + AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_INPUT, + AV8100_STANDBY_INTERRUPT_MASK_IPOL_LOW); + if (retval) { + dev_dbg(adev->dev, + "Failed to write the value to av8100 register\n"); + return -EFAULT; + } + + adev->params.ints_enabled = true; + + return 0; +} +EXPORT_SYMBOL(av8100_enable_interrupt); + +int av8100_reg_stby_w( + u8 cpd, u8 stby, u8 mclkrng) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Set register value */ + val = AV8100_STANDBY_CPD(cpd) | AV8100_STANDBY_STBY(stby) | + AV8100_STANDBY_MCLKRNG(mclkrng); + + /* Write to register */ + retval = register_write_internal(AV8100_STANDBY, val); + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_stby_w); + +static int av8100_5V_w(u8 denc_off, u8 hdmi_off, u8 on) +{ + u8 val; + int retval; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EINVAL; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Set register value. + * chip_version == 1 have one common off time + * chip_version > 1 support different off time for hdmi and tvout. */ + if (adev->chip_version == 1) + val = AV8100_HDMI_5_VOLT_TIME_OFF_TIME(hdmi_off) | + AV8100_HDMI_5_VOLT_TIME_ON_TIME(on); + else + val = AV8100_HDMI_5_VOLT_TIME_DAC_OFF_TIME(denc_off) | + AV8100_HDMI_5_VOLT_TIME_SU_OFF_TIME(hdmi_off) | + AV8100_HDMI_5_VOLT_TIME_ON_TIME(on); + + /* Write to register */ + retval = register_write_internal(AV8100_HDMI_5_VOLT_TIME, val); + + UNLOCK_AV8100_HW; + + return retval; +} + +int av8100_reg_hdmi_5_volt_time_w(u8 denc_off, u8 hdmi_off, u8 on) +{ + int retval; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EINVAL; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + retval = av8100_5V_w(denc_off, hdmi_off, on); + + /* Set vars */ + if (adev->chip_version > 1) + adev->params.denc_off_time = denc_off; + + adev->params.hdmi_off_time = hdmi_off; + if (on) + adev->params.on_time = on; + + return retval; +} +EXPORT_SYMBOL(av8100_reg_hdmi_5_volt_time_w); + +int av8100_reg_stby_int_mask_w( + u8 hpdm, u8 cpdm, u8 stbygpiocfg, u8 ipol) +{ + int retval; + u8 val; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EINVAL; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Set register value */ + val = AV8100_STANDBY_INTERRUPT_MASK_HPDM(hpdm) | + AV8100_STANDBY_INTERRUPT_MASK_CPDM(cpdm) | + AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG(stbygpiocfg) | + AV8100_STANDBY_INTERRUPT_MASK_IPOL(ipol); + + /* Write to register */ + retval = register_write_internal(AV8100_STANDBY_INTERRUPT_MASK, val); + + adev->params.hpdm = hpdm; + adev->params.cpdm = cpdm; + + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_stby_int_mask_w); + +int av8100_reg_stby_pend_int_w( + u8 hpdi, u8 cpdi, u8 oni, u8 bpdig) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Set register value */ + val = AV8100_STANDBY_PENDING_INTERRUPT_HPDI(hpdi) | + AV8100_STANDBY_PENDING_INTERRUPT_CPDI(cpdi) | + AV8100_STANDBY_PENDING_INTERRUPT_ONI(oni) | + AV8100_STANDBY_PENDING_INTERRUPT_BPDIG(bpdig); + + /* Write to register */ + retval = register_write_internal(AV8100_STANDBY_PENDING_INTERRUPT, val); + + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_stby_pend_int_w); + +int av8100_reg_gen_int_mask_w( + u8 eocm, u8 vsim, u8 vsom, u8 cecm, u8 hdcpm, u8 uovbm, u8 tem) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Set register value */ + val = AV8100_GENERAL_INTERRUPT_MASK_EOCM(eocm) | + AV8100_GENERAL_INTERRUPT_MASK_VSIM(vsim) | + AV8100_GENERAL_INTERRUPT_MASK_VSOM(vsom) | + AV8100_GENERAL_INTERRUPT_MASK_CECM(cecm) | + AV8100_GENERAL_INTERRUPT_MASK_HDCPM(hdcpm) | + AV8100_GENERAL_INTERRUPT_MASK_UOVBM(uovbm) | + AV8100_GENERAL_INTERRUPT_MASK_TEM(tem); + + /* Write to register */ + retval = register_write_internal(AV8100_GENERAL_INTERRUPT_MASK, val); + + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_gen_int_mask_w); + +int av8100_reg_gen_int_w( + u8 eoci, u8 vsii, u8 vsoi, u8 ceci, u8 hdcpi, u8 uovbi) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Set register value */ + val = AV8100_GENERAL_INTERRUPT_EOCI(eoci) | + AV8100_GENERAL_INTERRUPT_VSII(vsii) | + AV8100_GENERAL_INTERRUPT_VSOI(vsoi) | + AV8100_GENERAL_INTERRUPT_CECI(ceci) | + AV8100_GENERAL_INTERRUPT_HDCPI(hdcpi) | + AV8100_GENERAL_INTERRUPT_UOVBI(uovbi); + + /* Write to register */ + retval = register_write_internal(AV8100_GENERAL_INTERRUPT, val); + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_gen_int_w); + +int av8100_reg_gpio_conf_w( + u8 dat3dir, u8 dat3val, u8 dat2dir, u8 dat2val, u8 dat1dir, + u8 dat1val, u8 ucdbg) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Set register value */ + val = AV8100_GPIO_CONFIGURATION_DAT3DIR(dat3dir) | + AV8100_GPIO_CONFIGURATION_DAT3VAL(dat3val) | + AV8100_GPIO_CONFIGURATION_DAT2DIR(dat2dir) | + AV8100_GPIO_CONFIGURATION_DAT2VAL(dat2val) | + AV8100_GPIO_CONFIGURATION_DAT1DIR(dat1dir) | + AV8100_GPIO_CONFIGURATION_DAT1VAL(dat1val) | + AV8100_GPIO_CONFIGURATION_UCDBG(ucdbg); + + /* Write to register */ + retval = register_write_internal(AV8100_GPIO_CONFIGURATION, val); + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_gpio_conf_w); + +int av8100_reg_gen_ctrl_w( + u8 fdl, u8 hld, u8 wa, u8 ra) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Set register value */ + val = AV8100_GENERAL_CONTROL_FDL(fdl) | + AV8100_GENERAL_CONTROL_HLD(hld) | + AV8100_GENERAL_CONTROL_WA(wa) | + AV8100_GENERAL_CONTROL_RA(ra); + + /* Write to register */ + retval = register_write_internal(AV8100_GENERAL_CONTROL, val); + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_gen_ctrl_w); + +int av8100_reg_fw_dl_entry_w( + u8 mbyte_code_entry) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Set register value */ + val = AV8100_FIRMWARE_DOWNLOAD_ENTRY_MBYTE_CODE_ENTRY( + mbyte_code_entry); + + /* Write to register */ + retval = register_write_internal(AV8100_FIRMWARE_DOWNLOAD_ENTRY, val); + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_fw_dl_entry_w); + +int av8100_reg_w( + u8 offset, u8 value) +{ + int retval = 0; + struct i2c_client *i2c; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EINVAL; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + i2c = adev->config.client; + + /* Write to register */ + retval = write_single_byte(i2c, offset, value); + if (retval) { + dev_dbg(adev->dev, + "Failed to write the value to av8100 register\n"); + UNLOCK_AV8100_HW; + return -EFAULT; + } + + UNLOCK_AV8100_HW; + return 0; +} +EXPORT_SYMBOL(av8100_reg_w); + +int av8100_reg_stby_r( + u8 *cpd, u8 *stby, u8 *hpds, u8 *cpds, u8 *mclkrng) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Read from register */ + retval = register_read_internal(AV8100_STANDBY, &val); + + /* Set return params */ + if (cpd) + *cpd = AV8100_STANDBY_CPD_GET(val); + if (stby) + *stby = AV8100_STANDBY_STBY_GET(val); + if (hpds) + *hpds = AV8100_STANDBY_HPDS_GET(val); + if (cpds) + *cpds = AV8100_STANDBY_CPDS_GET(val); + if (mclkrng) + *mclkrng = AV8100_STANDBY_MCLKRNG_GET(val); + + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_stby_r); + +int av8100_reg_hdmi_5_volt_time_r( + u8 *denc_off_time, u8 *hdmi_off_time, u8 *on_time) +{ + int retval; + u8 val; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EINVAL; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Read from register */ + retval = register_read_internal(AV8100_HDMI_5_VOLT_TIME, &val); + + /* Set return params */ + if (adev->chip_version == 1) { + if (denc_off_time) + *denc_off_time = 0; + if (hdmi_off_time) + *hdmi_off_time = + AV8100_HDMI_5_VOLT_TIME_OFF_TIME_GET(val); + } else { + if (denc_off_time) + *denc_off_time = + AV8100_HDMI_5_VOLT_TIME_DAC_OFF_TIME_GET(val); + if (hdmi_off_time) + *hdmi_off_time = + AV8100_HDMI_5_VOLT_TIME_SU_OFF_TIME_GET(val); + } + + if (on_time) + *on_time = AV8100_HDMI_5_VOLT_TIME_ON_TIME_GET(val); + + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_hdmi_5_volt_time_r); + +int av8100_reg_stby_int_mask_r( + u8 *hpdm, u8 *cpdm, u8 *stbygpiocfg, u8 *ipol) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Read from register */ + retval = register_read_internal(AV8100_STANDBY_INTERRUPT_MASK, &val); + + /* Set return params */ + if (hpdm) + *hpdm = AV8100_STANDBY_INTERRUPT_MASK_HPDM_GET(val); + if (cpdm) + *cpdm = AV8100_STANDBY_INTERRUPT_MASK_CPDM_GET(val); + if (stbygpiocfg) + *stbygpiocfg = + AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_GET(val); + if (ipol) + *ipol = AV8100_STANDBY_INTERRUPT_MASK_IPOL_GET(val); + + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_stby_int_mask_r); + +int av8100_reg_stby_pend_int_r( + u8 *hpdi, u8 *cpdi, u8 *oni, u8 *sid) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Read from register */ + retval = register_read_internal(AV8100_STANDBY_PENDING_INTERRUPT, + &val); + + /* Set return params */ + if (hpdi) + *hpdi = AV8100_STANDBY_PENDING_INTERRUPT_HPDI_GET(val); + if (cpdi) + *cpdi = AV8100_STANDBY_PENDING_INTERRUPT_CPDI_GET(val); + if (oni) + *oni = AV8100_STANDBY_PENDING_INTERRUPT_ONI_GET(val); + if (sid) + *sid = AV8100_STANDBY_PENDING_INTERRUPT_SID_GET(val); + + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_stby_pend_int_r); + +int av8100_reg_gen_int_mask_r( + u8 *eocm, + u8 *vsim, + u8 *vsom, + u8 *cecm, + u8 *hdcpm, + u8 *uovbm, + u8 *tem) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Read from register */ + retval = register_read_internal(AV8100_GENERAL_INTERRUPT_MASK, &val); + + /* Set return params */ + if (eocm) + *eocm = AV8100_GENERAL_INTERRUPT_MASK_EOCM_GET(val); + if (vsim) + *vsim = AV8100_GENERAL_INTERRUPT_MASK_VSIM_GET(val); + if (vsom) + *vsom = AV8100_GENERAL_INTERRUPT_MASK_VSOM_GET(val); + if (cecm) + *cecm = AV8100_GENERAL_INTERRUPT_MASK_CECM_GET(val); + if (hdcpm) + *hdcpm = AV8100_GENERAL_INTERRUPT_MASK_HDCPM_GET(val); + if (uovbm) + *uovbm = AV8100_GENERAL_INTERRUPT_MASK_UOVBM_GET(val); + if (tem) + *tem = AV8100_GENERAL_INTERRUPT_MASK_TEM_GET(val); + + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_gen_int_mask_r); + +int av8100_reg_gen_int_r( + u8 *eoci, + u8 *vsii, + u8 *vsoi, + u8 *ceci, + u8 *hdcpi, + u8 *uovbi, + u8 *tei) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Read from register */ + retval = register_read_internal(AV8100_GENERAL_INTERRUPT, &val); + + /* Set return params */ + if (eoci) + *eoci = AV8100_GENERAL_INTERRUPT_EOCI_GET(val); + if (vsii) + *vsii = AV8100_GENERAL_INTERRUPT_VSII_GET(val); + if (vsoi) + *vsoi = AV8100_GENERAL_INTERRUPT_VSOI_GET(val); + if (ceci) + *ceci = AV8100_GENERAL_INTERRUPT_CECI_GET(val); + if (hdcpi) + *hdcpi = AV8100_GENERAL_INTERRUPT_HDCPI_GET(val); + if (uovbi) + *uovbi = AV8100_GENERAL_INTERRUPT_UOVBI_GET(val); + if (tei) + *tei = AV8100_GENERAL_INTERRUPT_TEI_GET(val); + + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_gen_int_r); + +int av8100_reg_gen_status_r( + u8 *cectxerr, + u8 *cecrec, + u8 *cectrx, + u8 *uc, + u8 *onuvb, + u8 *hdcps) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Read from register */ + retval = register_read_internal(AV8100_GENERAL_STATUS, &val); + + /* Set return params */ + if (cectxerr) + *cectxerr = AV8100_GENERAL_STATUS_CECTXERR_GET(val); + if (cecrec) + *cecrec = AV8100_GENERAL_STATUS_CECREC_GET(val); + if (cectrx) + *cectrx = AV8100_GENERAL_STATUS_CECTRX_GET(val); + if (uc) + *uc = AV8100_GENERAL_STATUS_UC_GET(val); + if (onuvb) + *onuvb = AV8100_GENERAL_STATUS_ONUVB_GET(val); + if (hdcps) + *hdcps = AV8100_GENERAL_STATUS_HDCPS_GET(val); + + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_gen_status_r); + +int av8100_reg_gpio_conf_r( + u8 *dat3dir, + u8 *dat3val, + u8 *dat2dir, + u8 *dat2val, + u8 *dat1dir, + u8 *dat1val, + u8 *ucdbg) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Read from register */ + retval = register_read_internal(AV8100_GPIO_CONFIGURATION, &val); + + /* Set return params */ + if (dat3dir) + *dat3dir = AV8100_GPIO_CONFIGURATION_DAT3DIR_GET(val); + if (dat3val) + *dat3val = AV8100_GPIO_CONFIGURATION_DAT3VAL_GET(val); + if (dat2dir) + *dat2dir = AV8100_GPIO_CONFIGURATION_DAT2DIR_GET(val); + if (dat2val) + *dat2val = AV8100_GPIO_CONFIGURATION_DAT2VAL_GET(val); + if (dat1dir) + *dat1dir = AV8100_GPIO_CONFIGURATION_DAT1DIR_GET(val); + if (dat1val) + *dat1val = AV8100_GPIO_CONFIGURATION_DAT1VAL_GET(val); + if (ucdbg) + *ucdbg = AV8100_GPIO_CONFIGURATION_UCDBG_GET(val); + + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_gpio_conf_r); + +int av8100_reg_gen_ctrl_r( + u8 *fdl, + u8 *hld, + u8 *wa, + u8 *ra) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Read from register */ + retval = register_read_internal(AV8100_GENERAL_CONTROL, &val); + /* Set return params */ + if (fdl) + *fdl = AV8100_GENERAL_CONTROL_FDL_GET(val); + if (hld) + *hld = AV8100_GENERAL_CONTROL_HLD_GET(val); + if (wa) + *wa = AV8100_GENERAL_CONTROL_WA_GET(val); + if (ra) + *ra = AV8100_GENERAL_CONTROL_RA_GET(val); + + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_gen_ctrl_r); + +int av8100_reg_fw_dl_entry_r( + u8 *mbyte_code_entry) +{ + int retval; + u8 val; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + /* Read from register */ + retval = register_read_internal(AV8100_FIRMWARE_DOWNLOAD_ENTRY, &val); + + /* Set return params */ + if (mbyte_code_entry) + *mbyte_code_entry = + AV8100_FIRMWARE_DOWNLOAD_ENTRY_MBYTE_CODE_ENTRY_GET(val); + + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_fw_dl_entry_r); + +int av8100_reg_r( + u8 offset, + u8 *value) +{ + int retval = 0; + struct i2c_client *i2c; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EINVAL; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + i2c = adev->config.client; + + /* Read from register */ + retval = read_single_byte(i2c, offset, value); + if (retval) { + dev_dbg(adev->dev, + "Failed to read the value from av8100 register\n"); + retval = -EFAULT; + goto av8100_register_read_out; + } + +av8100_register_read_out: + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_reg_r); + +int av8100_conf_get(enum av8100_command_type command_type, + union av8100_configuration *config) +{ + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EINVAL; + + if (av8100_status_get().av8100_state == AV8100_OPMODE_UNDEFINED) + return -EINVAL; + + /* Put configuration data to the corresponding data struct depending + * on command type */ + switch (command_type) { + case AV8100_COMMAND_VIDEO_INPUT_FORMAT: + memcpy(&config->video_input_format, + &adev->config.hdmi_video_input_cmd, + sizeof(struct av8100_video_input_format_cmd)); + break; + + case AV8100_COMMAND_AUDIO_INPUT_FORMAT: + memcpy(&config->audio_input_format, + &adev->config.hdmi_audio_input_cmd, + sizeof(struct av8100_audio_input_format_cmd)); + break; + + case AV8100_COMMAND_VIDEO_OUTPUT_FORMAT: + memcpy(&config->video_output_format, + &adev->config.hdmi_video_output_cmd, + sizeof(struct av8100_video_output_format_cmd)); + break; + + case AV8100_COMMAND_VIDEO_SCALING_FORMAT: + memcpy(&config->video_scaling_format, + &adev->config.hdmi_video_scaling_cmd, + sizeof(struct av8100_video_scaling_format_cmd)); + break; + + case AV8100_COMMAND_COLORSPACECONVERSION: + config->color_transform = adev->config.color_transform; + break; + + case AV8100_COMMAND_CEC_MESSAGE_WRITE: + memcpy(&config->cec_message_write_format, + &adev->config.hdmi_cec_message_write_cmd, + sizeof(struct av8100_cec_message_write_format_cmd)); + break; + + case AV8100_COMMAND_CEC_MESSAGE_READ_BACK: + memcpy(&config->cec_message_read_back_format, + &adev->config.hdmi_cec_message_read_back_cmd, + sizeof(struct av8100_cec_message_read_back_format_cmd)); + break; + + case AV8100_COMMAND_DENC: + memcpy(&config->denc_format, &adev->config.hdmi_denc_cmd, + sizeof(struct av8100_denc_format_cmd)); + break; + + case AV8100_COMMAND_HDMI: + memcpy(&config->hdmi_format, &adev->config.hdmi_cmd, + sizeof(struct av8100_hdmi_cmd)); + break; + + case AV8100_COMMAND_HDCP_SENDKEY: + memcpy(&config->hdcp_send_key_format, + &adev->config.hdmi_hdcp_send_key_cmd, + sizeof(struct av8100_hdcp_send_key_format_cmd)); + break; + + case AV8100_COMMAND_HDCP_MANAGEMENT: + memcpy(&config->hdcp_management_format, + &adev->config.hdmi_hdcp_management_format_cmd, + sizeof(struct av8100_hdcp_management_format_cmd)); + break; + + case AV8100_COMMAND_INFOFRAMES: + memcpy(&config->infoframes_format, + &adev->config.hdmi_infoframes_cmd, + sizeof(struct av8100_infoframes_format_cmd)); + break; + + case AV8100_COMMAND_EDID_SECTION_READBACK: + memcpy(&config->edid_section_readback_format, + &adev->config.hdmi_edid_section_readback_cmd, + sizeof(struct + av8100_edid_section_readback_format_cmd)); + break; + + case AV8100_COMMAND_PATTERNGENERATOR: + memcpy(&config->pattern_generator_format, + &adev->config.hdmi_pattern_generator_cmd, + sizeof(struct av8100_pattern_generator_format_cmd)); + break; + + case AV8100_COMMAND_FUSE_AES_KEY: + memcpy(&config->fuse_aes_key_format, + &adev->config.hdmi_fuse_aes_key_cmd, + sizeof(struct av8100_fuse_aes_key_format_cmd)); + break; + + default: + return -EINVAL; + break; + } + + return 0; +} +EXPORT_SYMBOL(av8100_conf_get); + +int av8100_conf_prep(enum av8100_command_type command_type, + union av8100_configuration *config) +{ + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!config || !adev) + return -EINVAL; + + /* Put configuration data to the corresponding data struct depending + * on command type */ + switch (command_type) { + case AV8100_COMMAND_VIDEO_INPUT_FORMAT: + memcpy(&adev->config.hdmi_video_input_cmd, + &config->video_input_format, + sizeof(struct av8100_video_input_format_cmd)); + break; + + case AV8100_COMMAND_AUDIO_INPUT_FORMAT: + memcpy(&adev->config.hdmi_audio_input_cmd, + &config->audio_input_format, + sizeof(struct av8100_audio_input_format_cmd)); + break; + + case AV8100_COMMAND_VIDEO_OUTPUT_FORMAT: + memcpy(&adev->config.hdmi_video_output_cmd, + &config->video_output_format, + sizeof(struct av8100_video_output_format_cmd)); + + /* Set params that depend on video output */ + av8100_config_video_output_dep(adev->config. + hdmi_video_output_cmd.video_output_cea_vesa); + break; + + case AV8100_COMMAND_VIDEO_SCALING_FORMAT: + memcpy(&adev->config.hdmi_video_scaling_cmd, + &config->video_scaling_format, + sizeof(struct av8100_video_scaling_format_cmd)); + break; + + case AV8100_COMMAND_COLORSPACECONVERSION: + adev->config.color_transform = config->color_transform; + break; + + case AV8100_COMMAND_CEC_MESSAGE_WRITE: + memcpy(&adev->config.hdmi_cec_message_write_cmd, + &config->cec_message_write_format, + sizeof(struct av8100_cec_message_write_format_cmd)); + break; + + case AV8100_COMMAND_CEC_MESSAGE_READ_BACK: + memcpy(&adev->config.hdmi_cec_message_read_back_cmd, + &config->cec_message_read_back_format, + sizeof(struct av8100_cec_message_read_back_format_cmd)); + break; + + case AV8100_COMMAND_DENC: + memcpy(&adev->config.hdmi_denc_cmd, &config->denc_format, + sizeof(struct av8100_denc_format_cmd)); + break; + + case AV8100_COMMAND_HDMI: + memcpy(&adev->config.hdmi_cmd, &config->hdmi_format, + sizeof(struct av8100_hdmi_cmd)); + break; + + case AV8100_COMMAND_HDCP_SENDKEY: + memcpy(&adev->config.hdmi_hdcp_send_key_cmd, + &config->hdcp_send_key_format, + sizeof(struct av8100_hdcp_send_key_format_cmd)); + break; + + case AV8100_COMMAND_HDCP_MANAGEMENT: + memcpy(&adev->config.hdmi_hdcp_management_format_cmd, + &config->hdcp_management_format, + sizeof(struct av8100_hdcp_management_format_cmd)); + break; + + case AV8100_COMMAND_INFOFRAMES: + memcpy(&adev->config.hdmi_infoframes_cmd, + &config->infoframes_format, + sizeof(struct av8100_infoframes_format_cmd)); + break; + + case AV8100_COMMAND_EDID_SECTION_READBACK: + memcpy(&adev->config.hdmi_edid_section_readback_cmd, + &config->edid_section_readback_format, + sizeof(struct + av8100_edid_section_readback_format_cmd)); + break; + + case AV8100_COMMAND_PATTERNGENERATOR: + memcpy(&adev->config.hdmi_pattern_generator_cmd, + &config->pattern_generator_format, + sizeof(struct av8100_pattern_generator_format_cmd)); + break; + + case AV8100_COMMAND_FUSE_AES_KEY: + memcpy(&adev->config.hdmi_fuse_aes_key_cmd, + &config->fuse_aes_key_format, + sizeof(struct av8100_fuse_aes_key_format_cmd)); + break; + + default: + return -EINVAL; + break; + } + + return 0; +} +EXPORT_SYMBOL(av8100_conf_prep); + +int av8100_conf_w(enum av8100_command_type command_type, + u8 *return_buffer_length, + u8 *return_buffer, enum interface_type if_type) +{ + int retval = 0; + u8 cmd_buffer[AV8100_COMMAND_MAX_LENGTH]; + u32 cmd_length = 0; + struct i2c_client *i2c; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EINVAL; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + if (return_buffer_length) + *return_buffer_length = 0; + + i2c = adev->config.client; + + memset(&cmd_buffer, 0x00, AV8100_COMMAND_MAX_LENGTH); + +#define PRNK_MODE(_m) dev_dbg(adev->dev, "cmd: " #_m "\n"); + + /* Fill the command buffer with configuration data */ + switch (command_type) { + case AV8100_COMMAND_VIDEO_INPUT_FORMAT: + PRNK_MODE(AV8100_COMMAND_VIDEO_INPUT_FORMAT); + configuration_video_input_get(adev, cmd_buffer, &cmd_length); + break; + + case AV8100_COMMAND_AUDIO_INPUT_FORMAT: + PRNK_MODE(AV8100_COMMAND_AUDIO_INPUT_FORMAT); + configuration_audio_input_get(adev, cmd_buffer, &cmd_length); + break; + + case AV8100_COMMAND_VIDEO_OUTPUT_FORMAT: + PRNK_MODE(AV8100_COMMAND_VIDEO_OUTPUT_FORMAT); + configuration_video_output_get(adev, cmd_buffer, &cmd_length); + break; + + case AV8100_COMMAND_VIDEO_SCALING_FORMAT: + PRNK_MODE(AV8100_COMMAND_VIDEO_SCALING_FORMAT); + configuration_video_scaling_get(adev, cmd_buffer, + &cmd_length); + break; + + case AV8100_COMMAND_COLORSPACECONVERSION: + PRNK_MODE(AV8100_COMMAND_COLORSPACECONVERSION); + configuration_colorspace_conversion_get(adev, cmd_buffer, + &cmd_length); + break; + + case AV8100_COMMAND_CEC_MESSAGE_WRITE: + PRNK_MODE(AV8100_COMMAND_CEC_MESSAGE_WRITE); + configuration_cec_message_write_get(adev, cmd_buffer, + &cmd_length); + break; + + case AV8100_COMMAND_CEC_MESSAGE_READ_BACK: + PRNK_MODE(AV8100_COMMAND_CEC_MESSAGE_READ_BACK); + configuration_cec_message_read_get(cmd_buffer, + &cmd_length); + break; + + case AV8100_COMMAND_DENC: + PRNK_MODE(AV8100_COMMAND_DENC); + configuration_denc_get(adev, cmd_buffer, &cmd_length); + break; + + case AV8100_COMMAND_HDMI: + PRNK_MODE(AV8100_COMMAND_HDMI); + configuration_hdmi_get(adev, cmd_buffer, &cmd_length); + break; + + case AV8100_COMMAND_HDCP_SENDKEY: + PRNK_MODE(AV8100_COMMAND_HDCP_SENDKEY); + configuration_hdcp_sendkey_get(adev, cmd_buffer, &cmd_length); + break; + + case AV8100_COMMAND_HDCP_MANAGEMENT: + PRNK_MODE(AV8100_COMMAND_HDCP_MANAGEMENT); + configuration_hdcp_management_get(adev, cmd_buffer, + &cmd_length); + break; + + case AV8100_COMMAND_INFOFRAMES: + PRNK_MODE(AV8100_COMMAND_INFOFRAMES); + configuration_infoframe_get(adev, cmd_buffer, &cmd_length); + break; + + case AV8100_COMMAND_EDID_SECTION_READBACK: + PRNK_MODE(AV8100_COMMAND_EDID_SECTION_READBACK); + av8100_edid_section_readback_get(adev, cmd_buffer, &cmd_length); + break; + + case AV8100_COMMAND_PATTERNGENERATOR: + PRNK_MODE(AV8100_COMMAND_PATTERNGENERATOR); + configuration_pattern_generator_get(adev, cmd_buffer, + &cmd_length); + break; + + case AV8100_COMMAND_FUSE_AES_KEY: + PRNK_MODE(AV8100_COMMAND_FUSE_AES_KEY); + configuration_fuse_aes_key_get(adev, cmd_buffer, &cmd_length); + break; + + default: + dev_dbg(adev->dev, "Invalid command type\n"); + retval = -EFAULT; + break; + } + + LOCK_AV8100_HW; + + if (if_type == I2C_INTERFACE) { + int cnt = 0; + int cnt_max; + + dev_dbg(adev->dev, "av8100_conf_w cmd_type:%02x length:%02x ", + command_type, cmd_length); + dev_dbg(adev->dev, "buffer: "); + while (cnt < cmd_length) { + dev_dbg(adev->dev, "%02x ", cmd_buffer[cnt]); + cnt++; + } + + /* Write the command buffer */ + retval = write_multi_byte(i2c, + AV8100_CMD_BUF_OFFSET, cmd_buffer, cmd_length); + if (retval) { + UNLOCK_AV8100_HW; + return retval; + } + + /* Write the command */ + retval = write_single_byte(i2c, AV8100_COMMAND_OFFSET, + command_type); + if (retval) { + UNLOCK_AV8100_HW; + return retval; + } + + + /* Get the first return byte */ + mdelay(AV8100_WAITTIME_1MS); + cnt = 0; + cnt_max = sizeof(waittime_retry) / sizeof(waittime_retry[0]); + retval = get_command_return_first(i2c, command_type); + while (retval && (cnt < cnt_max)) { + mdelay(waittime_retry[cnt]); + retval = get_command_return_first(i2c, command_type); + cnt++; + } + dev_dbg(adev->dev, "first return cnt:%d\n", cnt); + + if (retval) { + UNLOCK_AV8100_HW; + return retval; + } + + retval = get_command_return_data(i2c, command_type, cmd_buffer, + return_buffer_length, return_buffer); + } else if (if_type == DSI_INTERFACE) { + /* TODO */ + } else { + retval = -EINVAL; + dev_dbg(adev->dev, "Invalid command type\n"); + } + + if (command_type == AV8100_COMMAND_HDMI) { + adev->status.hdmi_on = ((adev->config.hdmi_cmd. + hdmi_mode == AV8100_HDMI_ON) && + (adev->config.hdmi_cmd.hdmi_format == AV8100_HDMI)); + } + + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_conf_w); + +int av8100_conf_w_raw(enum av8100_command_type command_type, + u8 buffer_length, + u8 *buffer, + u8 *return_buffer_length, + u8 *return_buffer) +{ + int retval = 0; + struct i2c_client *i2c; + int cnt; + int cnt_max; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EINVAL; + + if (av8100_status_get().av8100_state <= AV8100_OPMODE_SHUTDOWN) + return -EINVAL; + + LOCK_AV8100_HW; + + if (return_buffer_length) + *return_buffer_length = 0; + + i2c = adev->config.client; + + /* Write the command buffer */ + retval = write_multi_byte(i2c, + AV8100_CMD_BUF_OFFSET, buffer, buffer_length); + if (retval) + goto av8100_conf_w_raw_out; + + /* Write the command */ + retval = write_single_byte(i2c, AV8100_COMMAND_OFFSET, + command_type); + if (retval) + goto av8100_conf_w_raw_out; + + + /* Get the first return byte */ + mdelay(AV8100_WAITTIME_1MS); + cnt = 0; + cnt_max = sizeof(waittime_retry) / sizeof(waittime_retry[0]); + retval = get_command_return_first(i2c, command_type); + while (retval && (cnt < cnt_max)) { + mdelay(waittime_retry[cnt]); + retval = get_command_return_first(i2c, command_type); + cnt++; + } + dev_dbg(adev->dev, "first return cnt:%d\n", cnt); + if (retval) + goto av8100_conf_w_raw_out; + + retval = get_command_return_data(i2c, command_type, buffer, + return_buffer_length, return_buffer); + +av8100_conf_w_raw_out: + UNLOCK_AV8100_HW; + return retval; +} +EXPORT_SYMBOL(av8100_conf_w_raw); + +struct av8100_status av8100_status_get(void) +{ + struct av8100_status status = {0}; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (adev) + return adev->status; + else + return status; +} +EXPORT_SYMBOL(av8100_status_get); + +enum av8100_output_CEA_VESA av8100_video_output_format_get(int xres, + int yres, + int htot, + int vtot, + int pixelclk, + bool interlaced) +{ + enum av8100_output_CEA_VESA index = 1; + int yres_div = !interlaced ? 1 : 2; + int hres_div = 1; + long freq1; + long freq2; + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EINVAL; + + /* + * 720_576_I need a divider for hact and htot since + * these params need to be twice as large as expected in av8100_all_cea, + * which is used as input parameter to video input config. + */ + if ((xres == 720) && (yres == 576) && (interlaced == true)) + hres_div = 2; + + freq1 = 1000000 / htot * 1000000 / vtot / pixelclk + 1; + while (index < sizeof(av8100_all_cea)/sizeof(struct av8100_cea)) { + freq2 = av8100_all_cea[index].frequence / + av8100_all_cea[index].htotale / + av8100_all_cea[index].vtotale; + + dev_dbg(adev->dev, "freq1:%ld freq2:%ld\n", freq1, freq2); + if ((xres == av8100_all_cea[index].hactive / hres_div) && + (yres == av8100_all_cea[index].vactive * yres_div) && + (htot == av8100_all_cea[index].htotale / hres_div) && + (vtot == av8100_all_cea[index].vtotale) && + (abs(freq1 - freq2) < 2)) { + goto av8100_video_output_format_get_out; + } + index++; + } + +av8100_video_output_format_get_out: + dev_dbg(adev->dev, "av8100_video_output_format_get %d %d %d %d %d\n", + xres, yres, htot, vtot, index); + return index; +} +EXPORT_SYMBOL(av8100_video_output_format_get); + +void av8100_hdmi_event_cb_set(void (*hdmi_ev_cb)(enum av8100_hdmi_event)) +{ + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (adev) + adev->params.hdmi_ev_cb = hdmi_ev_cb; +} +EXPORT_SYMBOL(av8100_hdmi_event_cb_set); + +u8 av8100_ver_get(void) +{ + struct av8100_device *adev; + + adev = devnr_to_adev(AV8100_DEVNR_DEFAULT); + if (!adev) + return -EINVAL; + + return adev->chip_version; +} +EXPORT_SYMBOL(av8100_ver_get); + +static const struct color_conversion_cmd *get_color_transform_cmd( + struct av8100_device *adev, + enum av8100_color_transform transform) +{ + const struct color_conversion_cmd *result; + + switch (transform) { + case AV8100_COLOR_TRANSFORM_INDENTITY: + result = &col_trans_identity; + break; + case AV8100_COLOR_TRANSFORM_INDENTITY_CLAMP_YUV: + result = &col_trans_identity_clamp_yuv; + break; + case AV8100_COLOR_TRANSFORM_YUV_TO_RGB: + if (adev->chip_version == AV8100_CHIPVER_1) + result = &col_trans_yuv_to_rgb_v1; + else + result = &col_trans_yuv_to_rgb_v2; + break; + case AV8100_COLOR_TRANSFORM_YUV_TO_DENC: + result = &col_trans_yuv_to_denc; + break; + case AV8100_COLOR_TRANSFORM_RGB_TO_DENC: + result = &col_trans_rgb_to_denc; + break; + default: + dev_warn(adev->dev, "Unknown color space transform\n"); + result = &col_trans_identity; + break; + } + return result; +} + +static int av8100_open(struct inode *inode, struct file *filp) +{ + pr_debug("%s\n", __func__); + return 0; +} + +static int av8100_release(struct inode *inode, struct file *filp) +{ + pr_debug("%s\n", __func__); + return 0; +} + +static long av8100_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + return 0; +} + +int av8100_device_register(struct av8100_device *adev) +{ + adev->miscdev.minor = MISC_DYNAMIC_MINOR; + adev->miscdev.name = "av8100"; + adev->miscdev.fops = &av8100_fops; + + if (misc_register(&adev->miscdev)) { + pr_err("av8100 misc_register failed\n"); + return -EFAULT; + } + return 0; +} + +int av8100_init_device(struct av8100_device *adev, struct device *dev) +{ + adev->dev = dev; + + if (av8100_config_init(adev)) { + dev_info(dev, "av8100_config_init failed\n"); + return -EFAULT; + } + + if (av8100_params_init(adev)) { + dev_info(dev, "av8100_params_init failed\n"); + return -EFAULT; + } + return 0; +} + +static int __devinit av8100_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + int ret = 0; + struct av8100_platform_data *pdata = i2c_client->dev.platform_data; + struct device *dev; + struct av8100_device *adev; + + dev = &i2c_client->dev; + + dev_dbg(dev, "%s\n", __func__); + + /* Allocate device data */ + adev = kzalloc(sizeof(struct av8100_device), GFP_KERNEL); + if (!adev) { + dev_info(dev, "%s: Alloc failure\n", __func__); + return -ENOMEM; + } + + /* Add to list */ + list_add_tail(&adev->list, &av8100_device_list); + + av8100_device_register(adev); + + av8100_init_device(adev, dev); + + av8100_set_state(adev, AV8100_OPMODE_UNDEFINED); + + if (!i2c_check_functionality(i2c_client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_READ_WORD_DATA)) { + ret = -ENODEV; + dev_info(dev, "av8100 i2c_check_functionality failed\n"); + goto err1; + } + + init_waitqueue_head(&adev->event); + + adev->config.client = i2c_client; + adev->config.id = (struct i2c_device_id *) id; + i2c_set_clientdata(i2c_client, &adev->config); + + kthread_run(av8100_thread, adev, "av8100_thread"); + + /* Get regulator resource */ + if (pdata->regulator_pwr_id) { + adev->params.regulator_pwr = regulator_get(dev, + pdata->regulator_pwr_id); + if (IS_ERR(adev->params.regulator_pwr)) { + ret = PTR_ERR(adev->params.regulator_pwr); + dev_warn(dev, + "%s: Failed to get regulator '%s'\n", + __func__, pdata->regulator_pwr_id); + adev->params.regulator_pwr = NULL; + goto err1; + } + } + + /* Get clock resource */ + if (pdata->inputclk_id) { + adev->params.inputclk = clk_get(NULL, pdata->inputclk_id); + if (IS_ERR(adev->params.inputclk)) { + adev->params.inputclk = NULL; + dev_warn(dev, "%s: Failed to get clock '%s'\n", + __func__, pdata->inputclk_id); + } + } + + av8100_set_state(adev, AV8100_OPMODE_SHUTDOWN); + + + if (av8100_powerup1(adev)) { + dev_err(adev->dev, "av8100_powerup1 fail\n"); + ret = -EFAULT; + goto err1; + } + + /* Obtain the chip version */ + ret = av8100_reg_stby_pend_int_r(NULL, NULL, NULL, + &adev->chip_version); + if (ret) { + dev_err(adev->dev, "Failed to read chip version\n"); + goto err2; + } + + dev_info(adev->dev, "chip version:%d\n", adev->chip_version); + + switch (adev->chip_version) { + case AV8100_CHIPVER_1: + case AV8100_CHIPVER_2: + break; + + default: + dev_err(adev->dev, "Unsupported chip version:%d\n", + adev->chip_version); + ret = -EINVAL; + goto err2; + break; + } +err2: + (void) av8100_powerdown(); +err1: + return ret; +} + +static int __devexit av8100_remove(struct i2c_client *i2c_client) +{ + struct av8100_device *adev; + + adev = dev_to_adev(&i2c_client->dev); + if (!adev) + return -EFAULT; + + dev_dbg(adev->dev, "%s\n", __func__); + + if (adev->params.inputclk) + clk_put(adev->params.inputclk); + + /* Release regulator resource */ + if (adev->params.regulator_pwr) + regulator_put(adev->params.regulator_pwr); + + misc_deregister(&adev->miscdev); + + /* Remove from list */ + list_del(&adev->list); + + /* Free device data */ + kfree(adev); + + return 0; +} + +int av8100_init(void) +{ + pr_debug("%s\n", __func__); + + if (i2c_add_driver(&av8100_driver)) { + pr_err("av8100 i2c_add_driver failed\n"); + return -EFAULT; + } + + return 0; +} +module_init(av8100_init); + +void av8100_exit(void) +{ + pr_debug("%s\n", __func__); + + i2c_del_driver(&av8100_driver); +} +module_exit(av8100_exit); + +MODULE_AUTHOR("Per Persson <per.xb.persson@stericsson.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ST-Ericsson hdmi display driver"); diff --git a/drivers/video/av8100/av8100_regs.h b/drivers/video/av8100/av8100_regs.h new file mode 100644 index 00000000000..6ed9000987a --- /dev/null +++ b/drivers/video/av8100/av8100_regs.h @@ -0,0 +1,346 @@ + +#define AV8100_VAL2REG(__reg, __fld, __val) \ + (((__val) << __reg##_##__fld##_SHIFT) & __reg##_##__fld##_MASK) +#define AV8100_REG2VAL(__reg, __fld, __val) \ + (((__val) & __reg##_##__fld##_MASK) >> __reg##_##__fld##_SHIFT) + +#define AV8100_STANDBY 0x00000000 +#define AV8100_STANDBY_CPD_SHIFT 0 +#define AV8100_STANDBY_CPD_MASK 0x00000001 +#define AV8100_STANDBY_CPD_HIGH 1 +#define AV8100_STANDBY_CPD_LOW 0 +#define AV8100_STANDBY_CPD(__x) \ + AV8100_VAL2REG(AV8100_STANDBY, CPD, __x) +#define AV8100_STANDBY_CPD_GET(__x) \ + AV8100_REG2VAL(AV8100_STANDBY, CPD, __x) +#define AV8100_STANDBY_STBY_SHIFT 1 +#define AV8100_STANDBY_STBY_MASK 0x00000002 +#define AV8100_STANDBY_STBY_HIGH 1 +#define AV8100_STANDBY_STBY_LOW 0 +#define AV8100_STANDBY_STBY(__x) \ + AV8100_VAL2REG(AV8100_STANDBY, STBY, __x) +#define AV8100_STANDBY_STBY_GET(__x) \ + AV8100_REG2VAL(AV8100_STANDBY, STBY, __x) +#define AV8100_STANDBY_HPDS_SHIFT 2 +#define AV8100_STANDBY_HPDS_MASK 0x00000004 +#define AV8100_STANDBY_HPDS(__x) \ + AV8100_VAL2REG(AV8100_STANDBY, HPDS, __x) +#define AV8100_STANDBY_HPDS_GET(__x) \ + AV8100_REG2VAL(AV8100_STANDBY, HPDS, __x) +#define AV8100_STANDBY_CPDS_SHIFT 3 +#define AV8100_STANDBY_CPDS_MASK 0x00000008 +#define AV8100_STANDBY_CPDS(__x) \ + AV8100_VAL2REG(AV8100_STANDBY, CPDS, __x) +#define AV8100_STANDBY_CPDS_GET(__x) \ + AV8100_REG2VAL(AV8100_STANDBY, CPDS, __x) +#define AV8100_STANDBY_MCLKRNG_SHIFT 4 +#define AV8100_STANDBY_MCLKRNG_MASK 0x000000F0 +#define AV8100_STANDBY_MCLKRNG(__x) \ + AV8100_VAL2REG(AV8100_STANDBY, MCLKRNG, __x) +#define AV8100_STANDBY_MCLKRNG_GET(__x) \ + AV8100_REG2VAL(AV8100_STANDBY, MCLKRNG, __x) +#define AV8100_HDMI_5_VOLT_TIME 0x00000001 +#define AV8100_HDMI_5_VOLT_TIME_OFF_TIME_SHIFT 0 +#define AV8100_HDMI_5_VOLT_TIME_OFF_TIME_MASK 0x0000001F +#define AV8100_HDMI_5_VOLT_TIME_OFF_TIME(__x) \ + AV8100_VAL2REG(AV8100_HDMI_5_VOLT_TIME, OFF_TIME, __x) +#define AV8100_HDMI_5_VOLT_TIME_OFF_TIME_GET(__x) \ + AV8100_REG2VAL(AV8100_HDMI_5_VOLT_TIME, OFF_TIME, __x) +#define AV8100_HDMI_5_VOLT_TIME_DAC_OFF_TIME_SHIFT 0 +#define AV8100_HDMI_5_VOLT_TIME_DAC_OFF_TIME_MASK 0x00000003 +#define AV8100_HDMI_5_VOLT_TIME_DAC_OFF_TIME(__x) \ + AV8100_VAL2REG(AV8100_HDMI_5_VOLT_TIME, DAC_OFF_TIME, __x) +#define AV8100_HDMI_5_VOLT_TIME_DAC_OFF_TIME_GET(__x) \ + AV8100_REG2VAL(AV8100_HDMI_5_VOLT_TIME, DAC_OFF_TIME, __x) +#define AV8100_HDMI_5_VOLT_TIME_SU_OFF_TIME_SHIFT 2 +#define AV8100_HDMI_5_VOLT_TIME_SU_OFF_TIME_MASK 0x0000001C +#define AV8100_HDMI_5_VOLT_TIME_SU_OFF_TIME(__x) \ + AV8100_VAL2REG(AV8100_HDMI_5_VOLT_TIME, SU_OFF_TIME, __x) +#define AV8100_HDMI_5_VOLT_TIME_SU_OFF_TIME_GET(__x) \ + AV8100_REG2VAL(AV8100_HDMI_5_VOLT_TIME, SU_OFF_TIME, __x) +#define AV8100_HDMI_5_VOLT_TIME_ON_TIME_SHIFT 5 +#define AV8100_HDMI_5_VOLT_TIME_ON_TIME_MASK 0x000000E0 +#define AV8100_HDMI_5_VOLT_TIME_ON_TIME(__x) \ + AV8100_VAL2REG(AV8100_HDMI_5_VOLT_TIME, ON_TIME, __x) +#define AV8100_HDMI_5_VOLT_TIME_ON_TIME_GET(__x) \ + AV8100_REG2VAL(AV8100_HDMI_5_VOLT_TIME, ON_TIME, __x) +#define AV8100_STANDBY_INTERRUPT_MASK 0x00000002 +#define AV8100_STANDBY_INTERRUPT_MASK_HPDM_SHIFT 0 +#define AV8100_STANDBY_INTERRUPT_MASK_HPDM_MASK 0x00000001 +#define AV8100_STANDBY_INTERRUPT_MASK_HPDM_HIGH 1 +#define AV8100_STANDBY_INTERRUPT_MASK_HPDM_LOW 0 +#define AV8100_STANDBY_INTERRUPT_MASK_HPDM(__x) \ + AV8100_VAL2REG(AV8100_STANDBY_INTERRUPT_MASK, HPDM, __x) +#define AV8100_STANDBY_INTERRUPT_MASK_HPDM_GET(__x) \ + AV8100_REG2VAL(AV8100_STANDBY_INTERRUPT_MASK, HPDM, __x) +#define AV8100_STANDBY_INTERRUPT_MASK_CPDM_SHIFT 1 +#define AV8100_STANDBY_INTERRUPT_MASK_CPDM_MASK 0x00000002 +#define AV8100_STANDBY_INTERRUPT_MASK_CPDM_HIGH 1 +#define AV8100_STANDBY_INTERRUPT_MASK_CPDM_LOW 0 +#define AV8100_STANDBY_INTERRUPT_MASK_CPDM(__x) \ + AV8100_VAL2REG(AV8100_STANDBY_INTERRUPT_MASK, CPDM, __x) +#define AV8100_STANDBY_INTERRUPT_MASK_CPDM_GET(__x) \ + AV8100_REG2VAL(AV8100_STANDBY_INTERRUPT_MASK, CPDM, __x) +#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_SHIFT 2 +#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_MASK 0x0000000C +#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_INPUT 0x00 +#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_ALT 0x01 +#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_OUTPUT0 0x02 +#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_OUTPUT1 0x03 +#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG(__x) \ + AV8100_VAL2REG(AV8100_STANDBY_INTERRUPT_MASK, STBYGPIOCFG, __x) +#define AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_GET(__x) \ + AV8100_REG2VAL(AV8100_STANDBY_INTERRUPT_MASK, STBYGPIOCFG, __x) +#define AV8100_STANDBY_INTERRUPT_MASK_IPOL_SHIFT 7 +#define AV8100_STANDBY_INTERRUPT_MASK_IPOL_MASK 0x00000080 +#define AV8100_STANDBY_INTERRUPT_MASK_IPOL_HIGH 1 +#define AV8100_STANDBY_INTERRUPT_MASK_IPOL_LOW 0 +#define AV8100_STANDBY_INTERRUPT_MASK_IPOL(__x) \ + AV8100_VAL2REG(AV8100_STANDBY_INTERRUPT_MASK, IPOL, __x) +#define AV8100_STANDBY_INTERRUPT_MASK_IPOL_GET(__x) \ + AV8100_REG2VAL(AV8100_STANDBY_INTERRUPT_MASK, IPOL, __x) +#define AV8100_STANDBY_PENDING_INTERRUPT 0x00000003 +#define AV8100_STANDBY_PENDING_INTERRUPT_HPDI_SHIFT 0 +#define AV8100_STANDBY_PENDING_INTERRUPT_HPDI_MASK 0x00000001 +#define AV8100_STANDBY_PENDING_INTERRUPT_HPDI_HIGH 1 +#define AV8100_STANDBY_PENDING_INTERRUPT_HPDI_LOW 0 +#define AV8100_STANDBY_PENDING_INTERRUPT_HPDI(__x) \ + AV8100_VAL2REG(AV8100_STANDBY_PENDING_INTERRUPT, HPDI, __x) +#define AV8100_STANDBY_PENDING_INTERRUPT_HPDI_GET(__x) \ + AV8100_REG2VAL(AV8100_STANDBY_PENDING_INTERRUPT, HPDI, __x) +#define AV8100_STANDBY_PENDING_INTERRUPT_CPDI_SHIFT 1 +#define AV8100_STANDBY_PENDING_INTERRUPT_CPDI_MASK 0x00000002 +#define AV8100_STANDBY_PENDING_INTERRUPT_CPDI_HIGH 1 +#define AV8100_STANDBY_PENDING_INTERRUPT_CPDI_LOW 0 +#define AV8100_STANDBY_PENDING_INTERRUPT_CPDI(__x) \ + AV8100_VAL2REG(AV8100_STANDBY_PENDING_INTERRUPT, CPDI, __x) +#define AV8100_STANDBY_PENDING_INTERRUPT_CPDI_GET(__x) \ + AV8100_REG2VAL(AV8100_STANDBY_PENDING_INTERRUPT, CPDI, __x) +#define AV8100_STANDBY_PENDING_INTERRUPT_ONI_SHIFT 2 +#define AV8100_STANDBY_PENDING_INTERRUPT_ONI_MASK 0x00000004 +#define AV8100_STANDBY_PENDING_INTERRUPT_ONI_HIGH 1 +#define AV8100_STANDBY_PENDING_INTERRUPT_ONI_LOW 0 +#define AV8100_STANDBY_PENDING_INTERRUPT_ONI(__x) \ + AV8100_VAL2REG(AV8100_STANDBY_PENDING_INTERRUPT, ONI, __x) +#define AV8100_STANDBY_PENDING_INTERRUPT_ONI_GET(__x) \ + AV8100_REG2VAL(AV8100_STANDBY_PENDING_INTERRUPT, ONI, __x) +#define AV8100_STANDBY_PENDING_INTERRUPT_SID_SHIFT 4 +#define AV8100_STANDBY_PENDING_INTERRUPT_SID_MASK 0x000000F0 +#define AV8100_STANDBY_PENDING_INTERRUPT_SID(__x) \ + AV8100_VAL2REG(AV8100_STANDBY_PENDING_INTERRUPT, SID, __x) +#define AV8100_STANDBY_PENDING_INTERRUPT_SID_GET(__x) \ + AV8100_REG2VAL(AV8100_STANDBY_PENDING_INTERRUPT, SID, __x) +#define AV8100_STANDBY_PENDING_INTERRUPT_BPDIG_SHIFT 6 +#define AV8100_STANDBY_PENDING_INTERRUPT_BPDIG_MASK 0x00000040 +#define AV8100_STANDBY_PENDING_INTERRUPT_BPDIG_HIGH 1 +#define AV8100_STANDBY_PENDING_INTERRUPT_BPDIG_LOW 0 +#define AV8100_STANDBY_PENDING_INTERRUPT_BPDIG(__x) \ + AV8100_VAL2REG(AV8100_STANDBY_PENDING_INTERRUPT, BPDIG, __x) +#define AV8100_GENERAL_INTERRUPT_MASK 0x00000004 +#define AV8100_GENERAL_INTERRUPT_MASK_EOCM_SHIFT 0 +#define AV8100_GENERAL_INTERRUPT_MASK_EOCM_MASK 0x00000001 +#define AV8100_GENERAL_INTERRUPT_MASK_EOCM_HIGH 1 +#define AV8100_GENERAL_INTERRUPT_MASK_EOCM_LOW 0 +#define AV8100_GENERAL_INTERRUPT_MASK_EOCM(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT_MASK, EOCM, __x) +#define AV8100_GENERAL_INTERRUPT_MASK_EOCM_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT_MASK, EOCM, __x) +#define AV8100_GENERAL_INTERRUPT_MASK_VSIM_SHIFT 1 +#define AV8100_GENERAL_INTERRUPT_MASK_VSIM_MASK 0x00000002 +#define AV8100_GENERAL_INTERRUPT_MASK_VSIM_HIGH 1 +#define AV8100_GENERAL_INTERRUPT_MASK_VSIM_LOW 0 +#define AV8100_GENERAL_INTERRUPT_MASK_VSIM(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT_MASK, VSIM, __x) +#define AV8100_GENERAL_INTERRUPT_MASK_VSIM_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT_MASK, VSIM, __x) +#define AV8100_GENERAL_INTERRUPT_MASK_VSOM_SHIFT 2 +#define AV8100_GENERAL_INTERRUPT_MASK_VSOM_MASK 0x00000004 +#define AV8100_GENERAL_INTERRUPT_MASK_VSOM_HIGH 1 +#define AV8100_GENERAL_INTERRUPT_MASK_VSOM_LOW 0 +#define AV8100_GENERAL_INTERRUPT_MASK_VSOM(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT_MASK, VSOM, __x) +#define AV8100_GENERAL_INTERRUPT_MASK_VSOM_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT_MASK, VSOM, __x) +#define AV8100_GENERAL_INTERRUPT_MASK_CECM_SHIFT 3 +#define AV8100_GENERAL_INTERRUPT_MASK_CECM_MASK 0x00000008 +#define AV8100_GENERAL_INTERRUPT_MASK_CECM_HIGH 1 +#define AV8100_GENERAL_INTERRUPT_MASK_CECM_LOW 0 +#define AV8100_GENERAL_INTERRUPT_MASK_CECM(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT_MASK, CECM, __x) +#define AV8100_GENERAL_INTERRUPT_MASK_CECM_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT_MASK, CECM, __x) +#define AV8100_GENERAL_INTERRUPT_MASK_HDCPM_SHIFT 4 +#define AV8100_GENERAL_INTERRUPT_MASK_HDCPM_MASK 0x00000010 +#define AV8100_GENERAL_INTERRUPT_MASK_HDCPM_HIGH 1 +#define AV8100_GENERAL_INTERRUPT_MASK_HDCPM_LOW 0 +#define AV8100_GENERAL_INTERRUPT_MASK_HDCPM(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT_MASK, HDCPM, __x) +#define AV8100_GENERAL_INTERRUPT_MASK_HDCPM_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT_MASK, HDCPM, __x) +#define AV8100_GENERAL_INTERRUPT_MASK_UOVBM_SHIFT 5 +#define AV8100_GENERAL_INTERRUPT_MASK_UOVBM_MASK 0x00000020 +#define AV8100_GENERAL_INTERRUPT_MASK_UOVBM_HIGH 1 +#define AV8100_GENERAL_INTERRUPT_MASK_UOVBM_LOW 0 +#define AV8100_GENERAL_INTERRUPT_MASK_UOVBM(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT_MASK, UOVBM, __x) +#define AV8100_GENERAL_INTERRUPT_MASK_UOVBM_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT_MASK, UOVBM, __x) +#define AV8100_GENERAL_INTERRUPT_MASK_TEM_SHIFT 6 +#define AV8100_GENERAL_INTERRUPT_MASK_TEM_MASK 0x00000040 +#define AV8100_GENERAL_INTERRUPT_MASK_TEM_HIGH 1 +#define AV8100_GENERAL_INTERRUPT_MASK_TEM_LOW 0 +#define AV8100_GENERAL_INTERRUPT_MASK_TEM(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT_MASK, TEM, __x) +#define AV8100_GENERAL_INTERRUPT_MASK_TEM_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT_MASK, TEM, __x) +#define AV8100_GENERAL_INTERRUPT 0x00000005 +#define AV8100_GENERAL_INTERRUPT_EOCI_SHIFT 0 +#define AV8100_GENERAL_INTERRUPT_EOCI_MASK 0x00000001 +#define AV8100_GENERAL_INTERRUPT_EOCI(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT, EOCI, __x) +#define AV8100_GENERAL_INTERRUPT_EOCI_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT, EOCI, __x) +#define AV8100_GENERAL_INTERRUPT_VSII_SHIFT 1 +#define AV8100_GENERAL_INTERRUPT_VSII_MASK 0x00000002 +#define AV8100_GENERAL_INTERRUPT_VSII(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT, VSII, __x) +#define AV8100_GENERAL_INTERRUPT_VSII_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT, VSII, __x) +#define AV8100_GENERAL_INTERRUPT_VSOI_SHIFT 2 +#define AV8100_GENERAL_INTERRUPT_VSOI_MASK 0x00000004 +#define AV8100_GENERAL_INTERRUPT_VSOI(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT, VSOI, __x) +#define AV8100_GENERAL_INTERRUPT_VSOI_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT, VSOI, __x) +#define AV8100_GENERAL_INTERRUPT_CECI_SHIFT 3 +#define AV8100_GENERAL_INTERRUPT_CECI_MASK 0x00000008 +#define AV8100_GENERAL_INTERRUPT_CECI(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT, CECI, __x) +#define AV8100_GENERAL_INTERRUPT_CECI_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT, CECI, __x) +#define AV8100_GENERAL_INTERRUPT_HDCPI_SHIFT 4 +#define AV8100_GENERAL_INTERRUPT_HDCPI_MASK 0x00000010 +#define AV8100_GENERAL_INTERRUPT_HDCPI(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT, HDCPI, __x) +#define AV8100_GENERAL_INTERRUPT_HDCPI_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT, HDCPI, __x) +#define AV8100_GENERAL_INTERRUPT_UOVBI_SHIFT 5 +#define AV8100_GENERAL_INTERRUPT_UOVBI_MASK 0x00000020 +#define AV8100_GENERAL_INTERRUPT_UOVBI(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT, UOVBI, __x) +#define AV8100_GENERAL_INTERRUPT_UOVBI_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT, UOVBI, __x) +#define AV8100_GENERAL_INTERRUPT_TEI_SHIFT 6 +#define AV8100_GENERAL_INTERRUPT_TEI_MASK 0x00000040 +#define AV8100_GENERAL_INTERRUPT_TEI(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_INTERRUPT, TEI, __x) +#define AV8100_GENERAL_INTERRUPT_TEI_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_INTERRUPT, TEI, __x) +#define AV8100_GENERAL_STATUS 0x00000006 +#define AV8100_GENERAL_STATUS_CECTXERR_SHIFT 0 +#define AV8100_GENERAL_STATUS_CECTXERR_MASK 0x00000001 +#define AV8100_GENERAL_STATUS_CECTXERR_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_STATUS, CECTXERR, __x) +#define AV8100_GENERAL_STATUS_CECREC_SHIFT 1 +#define AV8100_GENERAL_STATUS_CECREC_MASK 0x00000002 +#define AV8100_GENERAL_STATUS_CECREC_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_STATUS, CECREC, __x) +#define AV8100_GENERAL_STATUS_CECTRX_SHIFT 2 +#define AV8100_GENERAL_STATUS_CECTRX_MASK 0x00000004 +#define AV8100_GENERAL_STATUS_CECTRX_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_STATUS, CECTRX, __x) +#define AV8100_GENERAL_STATUS_UC_SHIFT 3 +#define AV8100_GENERAL_STATUS_UC_MASK 0x00000008 +#define AV8100_GENERAL_STATUS_UC_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_STATUS, UC, __x) +#define AV8100_GENERAL_STATUS_ONUVB_SHIFT 4 +#define AV8100_GENERAL_STATUS_ONUVB_MASK 0x00000010 +#define AV8100_GENERAL_STATUS_ONUVB_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_STATUS, ONUVB, __x) +#define AV8100_GENERAL_STATUS_HDCPS_SHIFT 5 +#define AV8100_GENERAL_STATUS_HDCPS_MASK 0x000000E0 +#define AV8100_GENERAL_STATUS_HDCPS_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_STATUS, HDCPS, __x) +#define AV8100_GPIO_CONFIGURATION 0x00000007 +#define AV8100_GPIO_CONFIGURATION_DAT3DIR_SHIFT 0 +#define AV8100_GPIO_CONFIGURATION_DAT3DIR_MASK 0x00000001 +#define AV8100_GPIO_CONFIGURATION_DAT3DIR(__x) \ + AV8100_VAL2REG(AV8100_GPIO_CONFIGURATION, DAT3DIR, __x) +#define AV8100_GPIO_CONFIGURATION_DAT3DIR_GET(__x) \ + AV8100_REG2VAL(AV8100_GPIO_CONFIGURATION, DAT3DIR, __x) +#define AV8100_GPIO_CONFIGURATION_DAT3VAL_SHIFT 1 +#define AV8100_GPIO_CONFIGURATION_DAT3VAL_MASK 0x00000002 +#define AV8100_GPIO_CONFIGURATION_DAT3VAL(__x) \ + AV8100_VAL2REG(AV8100_GPIO_CONFIGURATION, DAT3VAL, __x) +#define AV8100_GPIO_CONFIGURATION_DAT3VAL_GET(__x) \ + AV8100_REG2VAL(AV8100_GPIO_CONFIGURATION, DAT3VAL, __x) +#define AV8100_GPIO_CONFIGURATION_DAT2DIR_SHIFT 2 +#define AV8100_GPIO_CONFIGURATION_DAT2DIR_MASK 0x00000004 +#define AV8100_GPIO_CONFIGURATION_DAT2DIR(__x) \ + AV8100_VAL2REG(AV8100_GPIO_CONFIGURATION, DAT2DIR, __x) +#define AV8100_GPIO_CONFIGURATION_DAT2DIR_GET(__x) \ + AV8100_REG2VAL(AV8100_GPIO_CONFIGURATION, DAT2DIR, __x) +#define AV8100_GPIO_CONFIGURATION_DAT2VAL_SHIFT 3 +#define AV8100_GPIO_CONFIGURATION_DAT2VAL_MASK 0x00000008 +#define AV8100_GPIO_CONFIGURATION_DAT2VAL(__x) \ + AV8100_VAL2REG(AV8100_GPIO_CONFIGURATION, DAT2VAL, __x) +#define AV8100_GPIO_CONFIGURATION_DAT2VAL_GET(__x) \ + AV8100_REG2VAL(AV8100_GPIO_CONFIGURATION, DAT2VAL, __x) +#define AV8100_GPIO_CONFIGURATION_DAT1DIR_SHIFT 4 +#define AV8100_GPIO_CONFIGURATION_DAT1DIR_MASK 0x00000010 +#define AV8100_GPIO_CONFIGURATION_DAT1DIR(__x) \ + AV8100_VAL2REG(AV8100_GPIO_CONFIGURATION, DAT1DIR, __x) +#define AV8100_GPIO_CONFIGURATION_DAT1DIR_GET(__x) \ + AV8100_REG2VAL(AV8100_GPIO_CONFIGURATION, DAT1DIR, __x) +#define AV8100_GPIO_CONFIGURATION_DAT1VAL_SHIFT 5 +#define AV8100_GPIO_CONFIGURATION_DAT1VAL_MASK 0x00000020 +#define AV8100_GPIO_CONFIGURATION_DAT1VAL(__x) \ + AV8100_VAL2REG(AV8100_GPIO_CONFIGURATION, DAT1VAL, __x) +#define AV8100_GPIO_CONFIGURATION_DAT1VAL_GET(__x) \ + AV8100_REG2VAL(AV8100_GPIO_CONFIGURATION, DAT1VAL, __x) +#define AV8100_GPIO_CONFIGURATION_UCDBG_SHIFT 6 +#define AV8100_GPIO_CONFIGURATION_UCDBG_MASK 0x00000040 +#define AV8100_GPIO_CONFIGURATION_UCDBG(__x) \ + AV8100_VAL2REG(AV8100_GPIO_CONFIGURATION, UCDBG, __x) +#define AV8100_GPIO_CONFIGURATION_UCDBG_GET(__x) \ + AV8100_REG2VAL(AV8100_GPIO_CONFIGURATION, UCDBG, __x) +#define AV8100_GENERAL_CONTROL 0x00000008 +#define AV8100_GENERAL_CONTROL_FDL_SHIFT 4 +#define AV8100_GENERAL_CONTROL_FDL_MASK 0x00000010 +#define AV8100_GENERAL_CONTROL_FDL_HIGH 1 +#define AV8100_GENERAL_CONTROL_FDL_LOW 0 +#define AV8100_GENERAL_CONTROL_FDL(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_CONTROL, FDL, __x) +#define AV8100_GENERAL_CONTROL_FDL_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_CONTROL, FDL, __x) +#define AV8100_GENERAL_CONTROL_HLD_SHIFT 5 +#define AV8100_GENERAL_CONTROL_HLD_MASK 0x00000020 +#define AV8100_GENERAL_CONTROL_HLD_HIGH 1 +#define AV8100_GENERAL_CONTROL_HLD_LOW 0 +#define AV8100_GENERAL_CONTROL_HLD(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_CONTROL, HLD, __x) +#define AV8100_GENERAL_CONTROL_HLD_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_CONTROL, HLD, __x) +#define AV8100_GENERAL_CONTROL_WA_SHIFT 6 +#define AV8100_GENERAL_CONTROL_WA_MASK 0x00000040 +#define AV8100_GENERAL_CONTROL_WA_HIGH 1 +#define AV8100_GENERAL_CONTROL_WA_LOW 0 +#define AV8100_GENERAL_CONTROL_WA(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_CONTROL, WA, __x) +#define AV8100_GENERAL_CONTROL_WA_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_CONTROL, WA, __x) +#define AV8100_GENERAL_CONTROL_RA_SHIFT 7 +#define AV8100_GENERAL_CONTROL_RA_MASK 0x00000080 +#define AV8100_GENERAL_CONTROL_RA_HIGH 1 +#define AV8100_GENERAL_CONTROL_RA_LOW 0 +#define AV8100_GENERAL_CONTROL_RA(__x) \ + AV8100_VAL2REG(AV8100_GENERAL_CONTROL, RA, __x) +#define AV8100_GENERAL_CONTROL_RA_GET(__x) \ + AV8100_REG2VAL(AV8100_GENERAL_CONTROL, RA, __x) +#define AV8100_FIRMWARE_DOWNLOAD_ENTRY 0x0000000F +#define AV8100_FIRMWARE_DOWNLOAD_ENTRY_MBYTE_CODE_ENTRY_SHIFT 0 +#define AV8100_FIRMWARE_DOWNLOAD_ENTRY_MBYTE_CODE_ENTRY_MASK 0x000000FF +#define AV8100_FIRMWARE_DOWNLOAD_ENTRY_MBYTE_CODE_ENTRY(__x) \ + AV8100_VAL2REG(AV8100_FIRMWARE_DOWNLOAD_ENTRY, MBYTE_CODE_ENTRY, __x) +#define AV8100_FIRMWARE_DOWNLOAD_ENTRY_MBYTE_CODE_ENTRY_GET(__x) \ + AV8100_REG2VAL(AV8100_FIRMWARE_DOWNLOAD_ENTRY, MBYTE_CODE_ENTRY, __x) diff --git a/drivers/video/av8100/hdmi.c b/drivers/video/av8100/hdmi.c new file mode 100644 index 00000000000..3159c4446f1 --- /dev/null +++ b/drivers/video/av8100/hdmi.c @@ -0,0 +1,2479 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * + * ST-Ericsson HDMI driver + * + * Author: Per Persson <per.xb.persson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/miscdevice.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/ioctl.h> +#include <linux/uaccess.h> +#include <video/av8100.h> +#include <video/hdmi.h> +#include <linux/poll.h> +#include <linux/mutex.h> +#include <linux/ctype.h> +#include "hdmi_loc.h" +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/list.h> + +#define SYSFS_EVENT_FILENAME "evread" +#define HDMI_DEVNR_DEFAULT 0 + +DEFINE_MUTEX(hdmi_events_mutex); +#define LOCK_HDMI_EVENTS mutex_lock(&hdmi_events_mutex) +#define UNLOCK_HDMI_EVENTS mutex_unlock(&hdmi_events_mutex) +#define EVENTS_MASK 0xFF + +struct hdmi_device { + struct list_head list; + struct miscdevice miscdev; + struct device *dev; + struct hdmi_sysfs_data sysfs_data; + int events; + int events_mask; + wait_queue_head_t event_wq; + bool events_received; + int devnr; +}; + +/* List of devices */ +static LIST_HEAD(hdmi_device_list); + +static ssize_t store_storeastext(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t store_plugdeten(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t store_edidread(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t show_edidread(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t store_ceceven(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t show_cecread(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t store_cecsend(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t store_infofrsend(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t store_hdcpeven(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t show_hdcpchkaesotp(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t store_hdcpfuseaes(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t show_hdcpfuseaes(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t store_hdcploadaes(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t show_hdcploadaes(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t store_hdcpauthencr(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t show_hdcpauthencr(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t show_hdcpstateget(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t show_evread(struct device *dev, struct device_attribute *attr, + char *buf); +static ssize_t store_evclr(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t store_audiocfg(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t show_plugstatus(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t store_poweronoff(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t show_poweronoff(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t store_evwakeup(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); + +static const struct device_attribute hdmi_sysfs_attrs[] = { + __ATTR(storeastext, S_IWUSR, NULL, store_storeastext), + __ATTR(plugdeten, S_IWUSR, NULL, store_plugdeten), + __ATTR(edidread, S_IRUGO | S_IWUSR, show_edidread, store_edidread), + __ATTR(ceceven, S_IWUSR, NULL, store_ceceven), + __ATTR(cecread, S_IRUGO, show_cecread, NULL), + __ATTR(cecsend, S_IWUSR, NULL, store_cecsend), + __ATTR(infofrsend, S_IWUSR, NULL, store_infofrsend), + __ATTR(hdcpeven, S_IWUSR, NULL, store_hdcpeven), + __ATTR(hdcpchkaesotp, S_IRUGO, show_hdcpchkaesotp, NULL), + __ATTR(hdcpfuseaes, S_IRUGO | S_IWUSR, show_hdcpfuseaes, + store_hdcpfuseaes), + __ATTR(hdcploadaes, S_IRUGO | S_IWUSR, show_hdcploadaes, + store_hdcploadaes), + __ATTR(hdcpauthencr, S_IRUGO | S_IWUSR, show_hdcpauthencr, + store_hdcpauthencr), + __ATTR(hdcpstateget, S_IRUGO, show_hdcpstateget, NULL), + __ATTR(evread, S_IRUGO, show_evread, NULL), + __ATTR(evclr, S_IWUSR, NULL, store_evclr), + __ATTR(audiocfg, S_IWUSR, NULL, store_audiocfg), + __ATTR(plugstatus, S_IRUGO, show_plugstatus, NULL), + __ATTR(poweronoff, S_IRUGO | S_IWUSR, show_poweronoff, + store_poweronoff), + __ATTR(evwakeup, S_IWUSR, NULL, store_evwakeup), + __ATTR_NULL +}; + +/* Hex to int conversion */ +static unsigned int htoi(const char *ptr) +{ + unsigned int value = 0; + char ch; + + if (!ptr) + return 0; + + ch = *ptr; + if (isdigit(ch)) + value = ch - '0'; + else + value = toupper(ch) - 'A' + 10; + + value <<= 4; + ch = *(++ptr); + + if (isdigit(ch)) + value += ch - '0'; + else + value += toupper(ch) - 'A' + 10; + + return value; +} + +static struct hdmi_device *dev_to_hdev(struct device *dev) +{ + /* Get device from list of devices */ + struct list_head *element; + struct hdmi_device *hdmi_dev; + int cnt = 0; + + list_for_each(element, &hdmi_device_list) { + hdmi_dev = list_entry(element, struct hdmi_device, list); + if (hdmi_dev->dev == dev) + return hdmi_dev; + cnt++; + } + + return NULL; +} + +static struct hdmi_device *devnr_to_hdev(int devnr) +{ + /* Get device from list of devices */ + struct list_head *element; + struct hdmi_device *hdmi_dev; + int cnt = 0; + + list_for_each(element, &hdmi_device_list) { + hdmi_dev = list_entry(element, struct hdmi_device, list); + if (cnt == devnr) + return hdmi_dev; + cnt++; + } + + return NULL; +} + +static int event_enable(struct hdmi_device *hdev, bool enable, + enum hdmi_event ev) +{ + struct kobject *kobj = &hdev->dev->kobj; + + dev_dbg(hdev->dev, "enable_event %d %02x\n", enable, ev); + if (enable) + hdev->events_mask |= ev; + else + hdev->events_mask &= ~ev; + + if (hdev->events & ev) { + /* Report pending event */ + /* Wake up application waiting for event via call to poll() */ + sysfs_notify(kobj, NULL, SYSFS_EVENT_FILENAME); + + LOCK_HDMI_EVENTS; + hdev->events_received = true; + UNLOCK_HDMI_EVENTS; + + wake_up_interruptible(&hdev->event_wq); + } + + return 0; +} + +static int plugdeten(struct hdmi_device *hdev, struct plug_detect *pldet) +{ + struct av8100_status status; + u8 denc_off_time = 0; + int retval; + + status = av8100_status_get(); + if (status.av8100_state < AV8100_OPMODE_STANDBY) { + if (av8100_powerup() != 0) { + dev_err(hdev->dev, "av8100_powerup failed\n"); + return -EINVAL; + } + } + + event_enable(hdev, pldet->hdmi_detect_enable != 0, + HDMI_EVENT_HDMI_PLUGIN); + event_enable(hdev, pldet->hdmi_detect_enable != 0, + HDMI_EVENT_HDMI_PLUGOUT); + + av8100_reg_hdmi_5_volt_time_r(&denc_off_time, NULL, NULL); + + retval = av8100_reg_hdmi_5_volt_time_w( + denc_off_time, + pldet->hdmi_off_time, + pldet->on_time); + + if (retval) { + dev_err(hdev->dev, "Failed to write the value to av8100 " + "register\n"); + return -EFAULT; + } + + return retval; +} + +static int edidread(struct hdmi_device *hdev, struct edid_read *edidread, + u8 *len, u8 *data) +{ + union av8100_configuration config; + struct av8100_status status; + + status = av8100_status_get(); + if (status.av8100_state < AV8100_OPMODE_STANDBY) { + if (av8100_powerup() != 0) { + dev_err(hdev->dev, "av8100_powerup failed\n"); + return -EINVAL; + } + } + + if (status.av8100_state <= AV8100_OPMODE_INIT) { + if (av8100_download_firmware(I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100 dl fw FAIL\n"); + return -EINVAL; + } + } + + config.edid_section_readback_format.address = edidread->address; + config.edid_section_readback_format.block_number = edidread->block_nr; + + dev_dbg(hdev->dev, "addr:%0x blnr:%0x", + config.edid_section_readback_format.address, + config.edid_section_readback_format.block_number); + + if (av8100_conf_prep(AV8100_COMMAND_EDID_SECTION_READBACK, + &config) != 0) { + dev_err(hdev->dev, "av8100_conf_prep FAIL\n"); + return -EINVAL; + } + + if (av8100_conf_w(AV8100_COMMAND_EDID_SECTION_READBACK, + len, data, I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100_conf_w FAIL\n"); + return -EINVAL; + } + + dev_dbg(hdev->dev, "len:%0x\n", *len); + + return 0; +} + +static int cecread(struct hdmi_device *hdev, u8 *src, u8 *dest, u8 *data_len, + u8 *data) +{ + union av8100_configuration config; + struct av8100_status status; + u8 buf_len; + u8 buff[HDMI_CEC_READ_MAXSIZE]; + + status = av8100_status_get(); + if (status.av8100_state < AV8100_OPMODE_STANDBY) { + if (av8100_powerup() != 0) { + dev_err(hdev->dev, "av8100_powerup failed\n"); + return -EINVAL; + } + } + + if (status.av8100_state <= AV8100_OPMODE_INIT) { + if (av8100_download_firmware(I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100 dl fw FAIL\n"); + return -EINVAL; + } + } + + if (av8100_conf_prep(AV8100_COMMAND_CEC_MESSAGE_READ_BACK, + &config) != 0) { + dev_err(hdev->dev, "av8100_conf_prep FAIL\n"); + return -EINVAL; + } + + if (av8100_conf_w(AV8100_COMMAND_CEC_MESSAGE_READ_BACK, + &buf_len, buff, I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100_conf_w FAIL\n"); + return -EINVAL; + } + + if (buf_len > 0) { + *src = (buff[0] & 0xF0) >> 4; + *dest = buff[0] & 0x0F; + *data_len = buf_len - 1; + memcpy(data, &buff[1], buf_len - 1); + } else + *data_len = 0; + + return 0; +} + +/* CEC tx status can be set or read */ +static bool cec_tx_status(struct hdmi_device *hdev, + enum cec_tx_status_action action) +{ + static bool cec_tx_busy; + + switch (action) { + case CEC_TX_SET_FREE: + cec_tx_busy = false; + dev_dbg(hdev->dev, "cec_tx_busy set:%d\n", cec_tx_busy); + break; + + case CEC_TX_SET_BUSY: + cec_tx_busy = true; + dev_dbg(hdev->dev, "cec_tx_busy set:%d\n", cec_tx_busy); + break; + + case CEC_TX_CHECK: + default: + dev_dbg(hdev->dev, "cec_tx_busy chk:%d\n", cec_tx_busy); + break; + } + + return cec_tx_busy; +} + +static int cecsend(struct hdmi_device *hdev, u8 src, u8 dest, u8 data_len, + u8 *data) +{ + union av8100_configuration config; + struct av8100_status status; + int cnt; + + status = av8100_status_get(); + if (status.av8100_state < AV8100_OPMODE_STANDBY) { + if (av8100_powerup() != 0) { + dev_err(hdev->dev, "av8100_powerup failed\n"); + return -EINVAL; + } + } + + if (status.av8100_state <= AV8100_OPMODE_INIT) { + if (av8100_download_firmware(I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100 dl fw FAIL\n"); + return -EINVAL; + } + } + + config.cec_message_write_format.buffer[0] = ((src & 0x0F) << 4) + + (dest & 0x0F); + config.cec_message_write_format.buffer_length = data_len + 1; + memcpy(&config.cec_message_write_format.buffer[1], data, data_len); + + if (av8100_conf_prep(AV8100_COMMAND_CEC_MESSAGE_WRITE, + &config) != 0) { + dev_err(hdev->dev, "av8100_conf_prep FAIL\n"); + return -EINVAL; + } + + if (av8100_enable_interrupt() != 0) { + dev_err(hdev->dev, "av8100_ei FAIL\n"); + return -EINVAL; + } + + cnt = 0; + while ((cnt < CECTX_TRY) && cec_tx_status(hdev, CEC_TX_CHECK)) { + /* Wait for pending CEC to be finished */ + msleep(CECTX_WAITTIME); + cnt++; + } + dev_dbg(hdev->dev, "cectxcnt:%d\n", cnt); + + if (av8100_conf_w(AV8100_COMMAND_CEC_MESSAGE_WRITE, + NULL, NULL, I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100_conf_w FAIL\n"); + return -EINVAL; + } + cec_tx_status(hdev, CEC_TX_SET_BUSY); + + return 0; +} + +static int infofrsend(struct hdmi_device *hdev, u8 type, u8 version, u8 crc, + u8 data_len, u8 *data) +{ + union av8100_configuration config; + struct av8100_status status; + + status = av8100_status_get(); + if (status.av8100_state < AV8100_OPMODE_STANDBY) { + if (av8100_powerup() != 0) { + dev_err(hdev->dev, "av8100_powerup failed\n"); + return -EINVAL; + } + } + + if (status.av8100_state <= AV8100_OPMODE_INIT) { + if (av8100_download_firmware(I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100 dl fw FAIL\n"); + return -EINVAL; + } + } + + if ((data_len < 1) || (data_len > HDMI_INFOFRAME_MAX_SIZE)) + return -EINVAL; + + config.infoframes_format.type = type; + config.infoframes_format.version = version; + config.infoframes_format.crc = crc; + config.infoframes_format.length = data_len; + memcpy(&config.infoframes_format.data, data, data_len); + if (av8100_conf_prep(AV8100_COMMAND_INFOFRAMES, + &config) != 0) { + dev_err(hdev->dev, "av8100_conf_prep FAIL\n"); + return -EINVAL; + } + + if (av8100_conf_w(AV8100_COMMAND_INFOFRAMES, + NULL, NULL, I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100_conf_w FAIL\n"); + return -EINVAL; + } + + return 0; +} + +static int hdcpchkaesotp(struct hdmi_device *hdev, u8 *crc, u8 *progged) +{ + union av8100_configuration config; + struct av8100_status status; + u8 buf_len; + u8 buf[2]; + + status = av8100_status_get(); + if (status.av8100_state < AV8100_OPMODE_STANDBY) { + if (av8100_powerup() != 0) { + dev_err(hdev->dev, "av8100_powerup failed\n"); + return -EINVAL; + } + } + + if (status.av8100_state <= AV8100_OPMODE_INIT) { + if (av8100_download_firmware(I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100 dl fw FAIL\n"); + return -EINVAL; + } + } + + config.fuse_aes_key_format.fuse_operation = AV8100_FUSE_READ; + memset(config.fuse_aes_key_format.key, 0, AV8100_FUSE_KEY_SIZE); + if (av8100_conf_prep(AV8100_COMMAND_FUSE_AES_KEY, + &config) != 0) { + dev_err(hdev->dev, "av8100_conf_prep FAIL\n"); + return -EINVAL; + } + + if (av8100_conf_w(AV8100_COMMAND_FUSE_AES_KEY, + &buf_len, buf, I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100_conf_w FAIL\n"); + return -EINVAL; + } + + if (buf_len == 2) { + *crc = buf[0]; + *progged = buf[1]; + } + + return 0; +} + +static int hdcpfuseaes(struct hdmi_device *hdev, u8 *key, u8 crc, u8 *result) +{ + union av8100_configuration config; + struct av8100_status status; + u8 buf_len; + u8 buf[2]; + + /* Default not OK */ + *result = HDMI_RESULT_NOT_OK; + + status = av8100_status_get(); + if (status.av8100_state < AV8100_OPMODE_STANDBY) { + if (av8100_powerup() != 0) { + dev_err(hdev->dev, "av8100_powerup failed\n"); + return -EINVAL; + } + } + + if (status.av8100_state <= AV8100_OPMODE_INIT) { + if (av8100_download_firmware(I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100 dl fw FAIL\n"); + return -EINVAL; + } + } + + config.fuse_aes_key_format.fuse_operation = AV8100_FUSE_WRITE; + memcpy(config.fuse_aes_key_format.key, key, AV8100_FUSE_KEY_SIZE); + if (av8100_conf_prep(AV8100_COMMAND_FUSE_AES_KEY, + &config) != 0) { + dev_err(hdev->dev, "av8100_conf_prep FAIL\n"); + return -EINVAL; + } + + if (av8100_conf_w(AV8100_COMMAND_FUSE_AES_KEY, + &buf_len, buf, I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100_conf_w FAIL\n"); + return -EINVAL; + } + + if (buf_len == 2) { + dev_dbg(hdev->dev, "buf[0]:%02x buf[1]:%02x\n", buf[0], buf[1]); + if ((crc == buf[0]) && (buf[1] == 1)) + /* OK */ + *result = HDMI_RESULT_OK; + else + *result = HDMI_RESULT_CRC_MISMATCH; + } + + return 0; +} + +static int hdcploadaes(struct hdmi_device *hdev, u8 block, u8 key_len, u8 *key, + u8 *result, u8 *crc32) +{ + union av8100_configuration config; + struct av8100_status status; + u8 buf_len; + u8 buf[CRC32_SIZE]; + + /* Default not OK */ + *result = HDMI_RESULT_NOT_OK; + + dev_dbg(hdev->dev, "%s block:%d\n", __func__, block); + + status = av8100_status_get(); + if (status.av8100_state < AV8100_OPMODE_STANDBY) { + if (av8100_powerup() != 0) { + dev_err(hdev->dev, "av8100_powerup failed\n"); + return -EINVAL; + } + } + + if (status.av8100_state <= AV8100_OPMODE_INIT) { + if (av8100_download_firmware(I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100 dl fw FAIL\n"); + return -EINVAL; + } + } + + config.hdcp_send_key_format.key_number = block; + config.hdcp_send_key_format.data_len = key_len; + memcpy(config.hdcp_send_key_format.data, key, key_len); + if (av8100_conf_prep(AV8100_COMMAND_HDCP_SENDKEY, &config) != 0) { + dev_err(hdev->dev, "av8100_conf_prep FAIL\n"); + return -EINVAL; + } + + if (av8100_conf_w(AV8100_COMMAND_HDCP_SENDKEY, + &buf_len, buf, I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100_conf_w FAIL\n"); + return -EINVAL; + } + + if ((buf_len == CRC32_SIZE) && (crc32)) { + memcpy(crc32, buf, CRC32_SIZE); + dev_dbg(hdev->dev, "crc32:%02x%02x%02x%02x\n", + crc32[0], crc32[1], crc32[2], crc32[3]); + } + + *result = HDMI_RESULT_OK; + + return 0; +} + +static int hdcpauthencr(struct hdmi_device *hdev, u8 auth_type, u8 encr_type, + u8 *len, u8 *data) +{ + union av8100_configuration config; + struct av8100_status status; + + status = av8100_status_get(); + if (status.av8100_state < AV8100_OPMODE_STANDBY) { + if (av8100_powerup() != 0) { + dev_err(hdev->dev, "av8100_powerup failed\n"); + return -EINVAL; + } + } + + if (status.av8100_state <= AV8100_OPMODE_INIT) { + if (av8100_download_firmware(I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100 dl fw FAIL\n"); + return -EINVAL; + } + } + + switch (auth_type) { + case HDMI_HDCP_AUTH_OFF: + default: + config.hdcp_management_format.req_type = + AV8100_HDCP_AUTH_REQ_OFF; + break; + + case HDMI_HDCP_AUTH_START: + config.hdcp_management_format.req_type = + AV8100_HDCP_AUTH_REQ_ON; + break; + + case HDMI_HDCP_AUTH_REV_LIST_REQ: + config.hdcp_management_format.req_type = + AV8100_HDCP_REV_LIST_REQ; + break; + case HDMI_HDCP_AUTH_CONT: + config.hdcp_management_format.req_type = + AV8100_HDCP_AUTH_CONT; + break; + } + + switch (encr_type) { + case HDMI_HDCP_ENCR_OESS: + default: + config.hdcp_management_format.encr_use = + AV8100_HDCP_ENCR_USE_OESS; + break; + + case HDMI_HDCP_ENCR_EESS: + config.hdcp_management_format.encr_use = + AV8100_HDCP_ENCR_USE_EESS; + break; + } + + if (av8100_conf_prep(AV8100_COMMAND_HDCP_MANAGEMENT, + &config) != 0) { + dev_err(hdev->dev, "av8100_conf_prep FAIL\n"); + return -EINVAL; + } + + if (av8100_conf_w(AV8100_COMMAND_HDCP_MANAGEMENT, + len, data, I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100_conf_w FAIL\n"); + return -EINVAL; + } + + return 0; +} + +static u8 events_read(struct hdmi_device *hdev) +{ + int ret; + + LOCK_HDMI_EVENTS; + ret = hdev->events; + dev_dbg(hdev->dev, "%s %02x\n", __func__, hdev->events); + UNLOCK_HDMI_EVENTS; + + return ret; +} + +static int events_clear(struct hdmi_device *hdev, u8 ev) +{ + dev_dbg(hdev->dev, "%s %02x\n", __func__, ev); + + LOCK_HDMI_EVENTS; + hdev->events &= ~ev & EVENTS_MASK; + UNLOCK_HDMI_EVENTS; + + return 0; +} + +static int event_wakeup(struct hdmi_device *hdev) +{ + struct kobject *kobj = &hdev->dev->kobj; + + dev_dbg(hdev->dev, "%s", __func__); + + LOCK_HDMI_EVENTS; + hdev->events |= HDMI_EVENT_WAKEUP; + hdev->events_received = true; + UNLOCK_HDMI_EVENTS; + + /* Wake up application waiting for event via call to poll() */ + sysfs_notify(kobj, NULL, SYSFS_EVENT_FILENAME); + wake_up_interruptible(&hdev->event_wq); + + return 0; +} + +static int audiocfg(struct hdmi_device *hdev, struct audio_cfg *cfg) +{ + union av8100_configuration config; + struct av8100_status status; + + status = av8100_status_get(); + if (status.av8100_state < AV8100_OPMODE_STANDBY) { + if (av8100_powerup() != 0) { + dev_err(hdev->dev, "av8100_powerup failed\n"); + return -EINVAL; + } + } + + if (status.av8100_state <= AV8100_OPMODE_INIT) { + if (av8100_download_firmware(I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100 dl fw FAIL\n"); + return -EINVAL; + } + } + + config.audio_input_format.audio_input_if_format = cfg->if_format; + config.audio_input_format.i2s_input_nb = cfg->i2s_entries; + config.audio_input_format.sample_audio_freq = cfg->freq; + config.audio_input_format.audio_word_lg = cfg->word_length; + config.audio_input_format.audio_format = cfg->format; + config.audio_input_format.audio_if_mode = cfg->if_mode; + config.audio_input_format.audio_mute = cfg->mute; + + if (av8100_conf_prep(AV8100_COMMAND_AUDIO_INPUT_FORMAT, + &config) != 0) { + dev_err(hdev->dev, "av8100_conf_prep FAIL\n"); + return -EINVAL; + } + + if (av8100_conf_w(AV8100_COMMAND_AUDIO_INPUT_FORMAT, + NULL, NULL, I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100_conf_w FAIL\n"); + return -EINVAL; + } + + return 0; +} + +/* sysfs */ +static ssize_t store_storeastext(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + if ((count != HDMI_STOREASTEXT_BIN_SIZE) && + (count != HDMI_STOREASTEXT_TEXT_SIZE) && + (count != HDMI_STOREASTEXT_TEXT_SIZE + 1)) + return -EINVAL; + + if ((count == HDMI_STOREASTEXT_BIN_SIZE) && (*buf == 0x1)) + hdev->sysfs_data.store_as_hextext = true; + else if (((count == HDMI_STOREASTEXT_TEXT_SIZE) || + (count == HDMI_STOREASTEXT_TEXT_SIZE + 1)) && (*buf == '0') && + (*(buf + 1) == '1')) { + hdev->sysfs_data.store_as_hextext = true; + } else { + hdev->sysfs_data.store_as_hextext = false; + } + + dev_dbg(hdev->dev, "store_as_hextext:%0d\n", + hdev->sysfs_data.store_as_hextext); + + return count; +} + +static ssize_t store_plugdeten(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + struct plug_detect plug_detect; + int index = 0; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + if (hdev->sysfs_data.store_as_hextext) { + if ((count != HDMI_PLUGDETEN_TEXT_SIZE) && + (count != HDMI_PLUGDETEN_TEXT_SIZE + 1)) + return -EINVAL; + plug_detect.hdmi_detect_enable = htoi(buf + index); + index += 2; + plug_detect.on_time = htoi(buf + index); + index += 2; + plug_detect.hdmi_off_time = htoi(buf + index); + index += 2; + } else { + if (count != HDMI_PLUGDETEN_BIN_SIZE) + return -EINVAL; + plug_detect.hdmi_detect_enable = *(buf + index++); + plug_detect.on_time = *(buf + index++); + plug_detect.hdmi_off_time = *(buf + index++); + } + + if (plugdeten(hdev, &plug_detect)) + return -EINVAL; + + return count; +} + +static ssize_t store_edidread(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + struct edid_read edid_read; + int index = 0; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + dev_dbg(hdev->dev, "count:%d\n", count); + + if (hdev->sysfs_data.store_as_hextext) { + if ((count != HDMI_EDIDREAD_TEXT_SIZE) && + (count != HDMI_EDIDREAD_TEXT_SIZE + 1)) + return -EINVAL; + edid_read.address = htoi(buf + index); + index += 2; + edid_read.block_nr = htoi(buf + index); + index += 2; + } else { + if (count != HDMI_EDIDREAD_BIN_SIZE) + return -EINVAL; + edid_read.address = *(buf + index++); + edid_read.block_nr = *(buf + index++); + } + + if (edidread(hdev, &edid_read, &hdev->sysfs_data.edid_data.buf_len, + hdev->sysfs_data.edid_data.buf)) + return -EINVAL; + + return count; +} + +static ssize_t show_edidread(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + int len; + int index = 0; + int cnt; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + len = hdev->sysfs_data.edid_data.buf_len; + + if (hdev->sysfs_data.store_as_hextext) { + snprintf(buf + index, 3, "%02x", len); + index += 2; + } else + *(buf + index++) = len; + + dev_dbg(hdev->dev, "len:%02x\n", len); + + cnt = 0; + while (cnt < len) { + if (hdev->sysfs_data.store_as_hextext) { + snprintf(buf + index, 3, "%02x", + hdev->sysfs_data.edid_data.buf[cnt]); + index += 2; + } else + *(buf + index++) = + hdev->sysfs_data.edid_data.buf[cnt]; + + dev_dbg(hdev->dev, "%02x ", + hdev->sysfs_data.edid_data.buf[cnt]); + + cnt++; + } + + if (hdev->sysfs_data.store_as_hextext) + index++; + + return index; +} + +static ssize_t store_ceceven(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + bool enable = false; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + if (hdev->sysfs_data.store_as_hextext) { + if ((count != HDMI_CECEVEN_TEXT_SIZE) && + (count != HDMI_CECEVEN_TEXT_SIZE + 1)) + return -EINVAL; + if ((*buf == '0') && (*(buf + 1) == '1')) + enable = true; + } else { + if (count != HDMI_CECEVEN_BIN_SIZE) + return -EINVAL; + if (*buf == 0x01) + enable = true; + } + + event_enable(hdev, enable, HDMI_EVENT_CEC | HDMI_EVENT_CECTXERR | + HDMI_EVENT_CECTX); + + return count; +} + +static ssize_t show_cecread(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + struct cec_rw cec_read; + int index = 0; + int cnt; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + if (cecread(hdev, &cec_read.src, &cec_read.dest, &cec_read.length, + cec_read.data)) + return -EINVAL; + + if (hdev->sysfs_data.store_as_hextext) { + snprintf(buf + index, 3, "%02x", cec_read.src); + index += 2; + snprintf(buf + index, 3, "%02x", cec_read.dest); + index += 2; + snprintf(buf + index, 3, "%02x", cec_read.length); + index += 2; + } else { + *(buf + index++) = cec_read.src; + *(buf + index++) = cec_read.dest; + *(buf + index++) = cec_read.length; + } + + dev_dbg(hdev->dev, "len:%02x\n", cec_read.length); + + cnt = 0; + while (cnt < cec_read.length) { + if (hdev->sysfs_data.store_as_hextext) { + snprintf(buf + index, 3, "%02x", cec_read.data[cnt]); + index += 2; + } else + *(buf + index++) = cec_read.data[cnt]; + + dev_dbg(hdev->dev, "%02x ", cec_read.data[cnt]); + + cnt++; + } + + if (hdev->sysfs_data.store_as_hextext) + index++; + + return index; +} + +static ssize_t store_cecsend(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + struct cec_rw cec_w; + int index = 0; + int cnt; + int store_as_text; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + if ((*buf == 'F') || (*buf == 'f')) + /* To be able to override bin format for test purpose */ + store_as_text = 1; + else + store_as_text = hdev->sysfs_data.store_as_hextext; + + if (store_as_text) { + if ((count < HDMI_CECSEND_TEXT_SIZE_MIN) || + (count > HDMI_CECSEND_TEXT_SIZE_MAX)) + return -EINVAL; + + cec_w.src = htoi(buf + index) & 0x0F; + index += 2; + cec_w.dest = htoi(buf + index); + index += 2; + cec_w.length = htoi(buf + index); + index += 2; + if (cec_w.length > HDMI_CEC_WRITE_MAXSIZE) + return -EINVAL; + cnt = 0; + while (cnt < cec_w.length) { + cec_w.data[cnt] = htoi(buf + index); + index += 2; + dev_dbg(hdev->dev, "%02x ", cec_w.data[cnt]); + cnt++; + } + } else { + if ((count < HDMI_CECSEND_BIN_SIZE_MIN) || + (count > HDMI_CECSEND_BIN_SIZE_MAX)) + return -EINVAL; + + cec_w.src = *(buf + index++); + cec_w.dest = *(buf + index++); + cec_w.length = *(buf + index++); + if (cec_w.length > HDMI_CEC_WRITE_MAXSIZE) + return -EINVAL; + memcpy(cec_w.data, buf + index, cec_w.length); + } + + if (cecsend(hdev, cec_w.src, cec_w.dest, cec_w.length, cec_w.data)) + return -EINVAL; + + return count; +} + +static ssize_t store_infofrsend(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + struct info_fr info_fr; + int index = 0; + int cnt; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + if (hdev->sysfs_data.store_as_hextext) { + if ((count < HDMI_INFOFRSEND_TEXT_SIZE_MIN) || + (count > HDMI_INFOFRSEND_TEXT_SIZE_MAX)) + return -EINVAL; + + info_fr.type = htoi(&buf[index]); + index += 2; + info_fr.ver = htoi(&buf[index]); + index += 2; + info_fr.crc = htoi(&buf[index]); + index += 2; + info_fr.length = htoi(&buf[index]); + index += 2; + + if (info_fr.length > HDMI_INFOFRAME_MAX_SIZE) + return -EINVAL; + cnt = 0; + while (cnt < info_fr.length) { + info_fr.data[cnt] = htoi(buf + index); + index += 2; + dev_dbg(hdev->dev, "%02x ", info_fr.data[cnt]); + cnt++; + } + } else { + if ((count < HDMI_INFOFRSEND_BIN_SIZE_MIN) || + (count > HDMI_INFOFRSEND_BIN_SIZE_MAX)) + return -EINVAL; + + info_fr.type = *(buf + index++); + info_fr.ver = *(buf + index++); + info_fr.crc = *(buf + index++); + info_fr.length = *(buf + index++); + + if (info_fr.length > HDMI_INFOFRAME_MAX_SIZE) + return -EINVAL; + memcpy(info_fr.data, buf + index, info_fr.length); + } + + if (infofrsend(hdev, info_fr.type, info_fr.ver, info_fr.crc, + info_fr.length, info_fr.data)) + return -EINVAL; + + return count; +} + +static ssize_t store_hdcpeven(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + bool enable = false; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + if (hdev->sysfs_data.store_as_hextext) { + if ((count != HDMI_HDCPEVEN_TEXT_SIZE) && + (count != HDMI_HDCPEVEN_TEXT_SIZE + 1)) + return -EINVAL; + if ((*buf == '0') && (*(buf + 1) == '1')) + enable = true; + } else { + if (count != HDMI_HDCPEVEN_BIN_SIZE) + return -EINVAL; + if (*buf == 0x01) + enable = true; + } + + event_enable(hdev, enable, HDMI_EVENT_HDCP); + + return count; +} + +static ssize_t show_hdcpchkaesotp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + u8 crc; + u8 progged; + int index = 0; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + if (hdcpchkaesotp(hdev, &crc, &progged)) + return -EINVAL; + + if (hdev->sysfs_data.store_as_hextext) { + snprintf(buf + index, 3, "%02x", progged); + index += 2; + } else { + *(buf + index++) = progged; + } + + dev_dbg(hdev->dev, "progged:%02x\n", progged); + + if (hdev->sysfs_data.store_as_hextext) + index++; + + return index; +} + +static ssize_t store_hdcpfuseaes(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + struct hdcp_fuseaes hdcp_fuseaes; + int index = 0; + int cnt; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + /* Default not OK */ + hdev->sysfs_data.fuse_result = HDMI_RESULT_NOT_OK; + + if (hdev->sysfs_data.store_as_hextext) { + if ((count != HDMI_HDCP_FUSEAES_TEXT_SIZE) && + (count != HDMI_HDCP_FUSEAES_TEXT_SIZE + 1)) + return -EINVAL; + + cnt = 0; + while (cnt < HDMI_HDCP_FUSEAES_KEYSIZE) { + hdcp_fuseaes.key[cnt] = htoi(buf + index); + index += 2; + dev_dbg(hdev->dev, "%02x ", hdcp_fuseaes.key[cnt]); + cnt++; + } + hdcp_fuseaes.crc = htoi(&buf[index]); + index += 2; + dev_dbg(hdev->dev, "%02x ", hdcp_fuseaes.crc); + } else { + if (count != HDMI_HDCP_FUSEAES_BIN_SIZE) + return -EINVAL; + + memcpy(hdcp_fuseaes.key, buf + index, + HDMI_HDCP_FUSEAES_KEYSIZE); + index += HDMI_HDCP_FUSEAES_KEYSIZE; + hdcp_fuseaes.crc = *(buf + index++); + } + + if (hdcpfuseaes(hdev, hdcp_fuseaes.key, hdcp_fuseaes.crc, + &hdcp_fuseaes.result)) + return -EINVAL; + + dev_dbg(hdev->dev, "fuseresult:%02x ", hdcp_fuseaes.result); + + hdev->sysfs_data.fuse_result = hdcp_fuseaes.result; + + return count; +} + +static ssize_t show_hdcpfuseaes(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + int index = 0; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + if (hdev->sysfs_data.store_as_hextext) { + snprintf(buf + index, 3, "%02x", hdev->sysfs_data.fuse_result); + index += 2; + } else + *(buf + index++) = hdev->sysfs_data.fuse_result; + + dev_dbg(hdev->dev, "status:%02x\n", hdev->sysfs_data.fuse_result); + + if (hdev->sysfs_data.store_as_hextext) + index++; + + return index; +} + +static ssize_t store_hdcploadaes(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + struct hdcp_loadaesone hdcp_loadaes; + int index = 0; + int block_cnt; + int cnt; + u8 crc32_rcvd[CRC32_SIZE]; + u8 crc; + u8 progged; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + /* Default not OK */ + hdev->sysfs_data.loadaes_result = HDMI_RESULT_NOT_OK; + + if (hdcpchkaesotp(hdev, &crc, &progged)) + return -EINVAL; + + if (!progged) { + /* AES is not fused */ + hdcp_loadaes.result = HDMI_AES_NOT_FUSED; + goto store_hdcploadaes_err; + } + + if (hdev->sysfs_data.store_as_hextext) { + if ((count != HDMI_HDCP_LOADAES_TEXT_SIZE) && + (count != HDMI_HDCP_LOADAES_TEXT_SIZE + 1)) { + dev_err(hdev->dev, "%s", "count mismatch\n"); + return -EINVAL; + } + + /* AES */ + block_cnt = 0; + while (block_cnt < HDMI_HDCP_AES_NR_OF_BLOCKS) { + cnt = 0; + while (cnt < HDMI_HDCP_AES_KEYSIZE) { + hdcp_loadaes.key[cnt] = htoi(buf + index); + index += 2; + dev_dbg(hdev->dev, "%02x ", + hdcp_loadaes.key[cnt]); + cnt++; + } + + if (hdcploadaes(hdev, + block_cnt + HDMI_HDCP_AES_BLOCK_START, + HDMI_HDCP_AES_KEYSIZE, + hdcp_loadaes.key, + &hdcp_loadaes.result, + crc32_rcvd)) { + dev_err(hdev->dev, "%s %d\n", + "hdcploadaes err aes block", + block_cnt + HDMI_HDCP_AES_BLOCK_START); + return -EINVAL; + } + + if (hdcp_loadaes.result) + goto store_hdcploadaes_err; + + block_cnt++; + } + + /* KSV */ + memset(hdcp_loadaes.key, 0, HDMI_HDCP_AES_KSVZEROESSIZE); + cnt = HDMI_HDCP_AES_KSVZEROESSIZE; + while (cnt < HDMI_HDCP_AES_KSVSIZE + + HDMI_HDCP_AES_KSVZEROESSIZE) { + hdcp_loadaes.key[cnt] = + htoi(&buf[index]); + index += 2; + dev_dbg(hdev->dev, "%02x ", hdcp_loadaes.key[cnt]); + cnt++; + } + + if (hdcploadaes(hdev, HDMI_HDCP_KSV_BLOCK, + HDMI_HDCP_AES_KSVSIZE + + HDMI_HDCP_AES_KSVZEROESSIZE, + hdcp_loadaes.key, + &hdcp_loadaes.result, + NULL)) { + dev_err(hdev->dev, + "%s %d\n", "hdcploadaes err in ksv\n", + block_cnt + HDMI_HDCP_AES_BLOCK_START); + return -EINVAL; + } + + if (hdcp_loadaes.result) + goto store_hdcploadaes_err; + + /* CRC32 */ + for (cnt = 0; cnt < CRC32_SIZE; cnt++) { + hdcp_loadaes.crc32[cnt] = htoi(buf + index); + index += 2; + } + + if (memcmp(hdcp_loadaes.crc32, crc32_rcvd, CRC32_SIZE)) { + dev_dbg(hdev->dev, "crc32exp:%02x%02x%02x%02x\n", + hdcp_loadaes.crc32[0], + hdcp_loadaes.crc32[1], + hdcp_loadaes.crc32[2], + hdcp_loadaes.crc32[3]); + hdcp_loadaes.result = HDMI_RESULT_CRC_MISMATCH; + goto store_hdcploadaes_err; + } + } else { + if (count != HDMI_HDCP_LOADAES_BIN_SIZE) { + dev_err(hdev->dev, "%s", "count mismatch\n"); + return -EINVAL; + } + + /* AES */ + block_cnt = 0; + while (block_cnt < HDMI_HDCP_AES_NR_OF_BLOCKS) { + memcpy(hdcp_loadaes.key, buf + index, + HDMI_HDCP_AES_KEYSIZE); + index += HDMI_HDCP_AES_KEYSIZE; + + if (hdcploadaes(hdev, + block_cnt + HDMI_HDCP_AES_BLOCK_START, + HDMI_HDCP_AES_KEYSIZE, + hdcp_loadaes.key, + &hdcp_loadaes.result, + crc32_rcvd)) { + dev_err(hdev->dev, "%s %d\n", + "hdcploadaes err aes block", + block_cnt + HDMI_HDCP_AES_BLOCK_START); + return -EINVAL; + } + + if (hdcp_loadaes.result) + goto store_hdcploadaes_err; + + block_cnt++; + } + + /* KSV */ + memset(hdcp_loadaes.key, 0, HDMI_HDCP_AES_KSVZEROESSIZE); + memcpy(hdcp_loadaes.key + HDMI_HDCP_AES_KSVZEROESSIZE, + buf + index, + HDMI_HDCP_AES_KSVSIZE); + index += HDMI_HDCP_AES_KSVSIZE; + + if (hdcploadaes(hdev, HDMI_HDCP_KSV_BLOCK, + HDMI_HDCP_AES_KSVSIZE + + HDMI_HDCP_AES_KSVZEROESSIZE, + hdcp_loadaes.key, + &hdcp_loadaes.result, + NULL)) { + dev_err(hdev->dev, "%s %d\n", + "hdcploadaes err in ksv\n", + block_cnt + HDMI_HDCP_AES_BLOCK_START); + return -EINVAL; + } + + memcpy(hdcp_loadaes.crc32, buf + index, CRC32_SIZE); + index += CRC32_SIZE; + + /* CRC32 */ + if (memcmp(hdcp_loadaes.crc32, crc32_rcvd, CRC32_SIZE)) { + dev_dbg(hdev->dev, "crc32exp:%02x%02x%02x%02x\n", + hdcp_loadaes.crc32[0], + hdcp_loadaes.crc32[1], + hdcp_loadaes.crc32[2], + hdcp_loadaes.crc32[3]); + hdcp_loadaes.result = HDMI_RESULT_CRC_MISMATCH; + } + } + +store_hdcploadaes_err: + hdev->sysfs_data.loadaes_result = hdcp_loadaes.result; + return count; +} + +static ssize_t show_hdcploadaes(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + int index = 0; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + if (hdev->sysfs_data.store_as_hextext) { + snprintf(buf + index, 3, "%02x", + hdev->sysfs_data.loadaes_result); + index += 2; + } else + *(buf + index++) = hdev->sysfs_data.loadaes_result; + + dev_dbg(hdev->dev, "result:%02x\n", hdev->sysfs_data.loadaes_result); + + if (hdev->sysfs_data.store_as_hextext) + index++; + + return index; +} + +static ssize_t store_hdcpauthencr(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + struct hdcp_authencr hdcp_authencr; + int index = 0; + u8 crc; + u8 progged; + int result = HDMI_RESULT_NOT_OK; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + /* Default */ + hdev->sysfs_data.authencr.buf_len = 0; + + if (hdcpchkaesotp(hdev, &crc, &progged)) { + result = HDMI_AES_NOT_FUSED; + goto store_hdcpauthencr_end; + } + + if (!progged) { + /* AES is not fused */ + result = HDMI_AES_NOT_FUSED; + goto store_hdcpauthencr_end; + } + + if (hdev->sysfs_data.store_as_hextext) { + if ((count != HDMI_HDCPAUTHENCR_TEXT_SIZE) && + (count != HDMI_HDCPAUTHENCR_TEXT_SIZE + 1)) + goto store_hdcpauthencr_end; + + hdcp_authencr.auth_type = htoi(buf + index); + index += 2; + hdcp_authencr.encr_type = htoi(buf + index); + index += 2; + } else { + if (count != HDMI_HDCPAUTHENCR_BIN_SIZE) + goto store_hdcpauthencr_end; + + hdcp_authencr.auth_type = *(buf + index++); + hdcp_authencr.encr_type = *(buf + index++); + } + + if (hdcpauthencr(hdev, hdcp_authencr.auth_type, hdcp_authencr.encr_type, + &hdev->sysfs_data.authencr.buf_len, + hdev->sysfs_data.authencr.buf)) + goto store_hdcpauthencr_end; + + result = HDMI_RESULT_OK; + +store_hdcpauthencr_end: + hdev->sysfs_data.authencr.result = result; + return count; +} + +static ssize_t show_hdcpauthencr(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + int len; + int index = 0; + int cnt; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + /* result */ + if (hdev->sysfs_data.store_as_hextext) { + snprintf(buf + index, 3, "%02x", + hdev->sysfs_data.authencr.result); + index += 2; + } else + *(buf + index++) = hdev->sysfs_data.authencr.result; + + dev_dbg(hdev->dev, "result:%02x\n", hdev->sysfs_data.authencr.result); + + /* resp_size */ + len = hdev->sysfs_data.authencr.buf_len; + if (len > AUTH_BUF_LEN) + len = AUTH_BUF_LEN; + dev_dbg(hdev->dev, "resp_size:%d\n", len); + + /* resp */ + cnt = 0; + while (cnt < len) { + if (hdev->sysfs_data.store_as_hextext) { + snprintf(buf + index, 3, "%02x", + hdev->sysfs_data.authencr.buf[cnt]); + index += 2; + + dev_dbg(hdev->dev, "%02x ", + hdev->sysfs_data.authencr.buf[cnt]); + + } else + *(buf + index++) = hdev->sysfs_data.authencr.buf[cnt]; + + cnt++; + } + + if (hdev->sysfs_data.store_as_hextext) + index++; + + return index; +} + +static ssize_t show_hdcpstateget(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + u8 hdcp_state; + int index = 0; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + if (av8100_reg_gen_status_r(NULL, NULL, NULL, NULL, NULL, &hdcp_state)) + return -EINVAL; + + if (hdev->sysfs_data.store_as_hextext) { + snprintf(buf + index, 3, "%02x", hdcp_state); + index += 2; + } else + *(buf + index++) = hdcp_state; + + dev_dbg(hdev->dev, "status:%02x\n", hdcp_state); + + if (hdev->sysfs_data.store_as_hextext) + index++; + + return index; +} + +static ssize_t show_evread(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + int index = 0; + u8 ev; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + ev = events_read(hdev); + + if (hdev->sysfs_data.store_as_hextext) { + snprintf(buf + index, 3, "%02x", ev); + index += 2; + } else + *(buf + index++) = ev; + + if (hdev->sysfs_data.store_as_hextext) + index++; + + /* Events are read: clear events */ + events_clear(hdev, EVENTS_MASK); + + return index; +} + +static ssize_t store_evclr(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + u8 ev; + int index = 0; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + if (hdev->sysfs_data.store_as_hextext) { + if ((count != HDMI_EVCLR_TEXT_SIZE) && + (count != HDMI_EVCLR_TEXT_SIZE + 1)) + return -EINVAL; + + ev = htoi(&buf[index]); + index += 2; + } else { + if (count != HDMI_EVCLR_BIN_SIZE) + return -EINVAL; + + ev = *(buf + index++); + } + + events_clear(hdev, ev); + + return count; +} + +static ssize_t store_audiocfg(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + struct audio_cfg audio_cfg; + int index = 0; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + if (hdev->sysfs_data.store_as_hextext) { + if ((count != HDMI_AUDIOCFG_TEXT_SIZE) && + (count != HDMI_AUDIOCFG_TEXT_SIZE + 1)) + return -EINVAL; + + audio_cfg.if_format = htoi(&buf[index]); + index += 2; + audio_cfg.i2s_entries = htoi(&buf[index]); + index += 2; + audio_cfg.freq = htoi(&buf[index]); + index += 2; + audio_cfg.word_length = htoi(&buf[index]); + index += 2; + audio_cfg.format = htoi(&buf[index]); + index += 2; + audio_cfg.if_mode = htoi(&buf[index]); + index += 2; + audio_cfg.mute = htoi(&buf[index]); + index += 2; + } else { + if (count != HDMI_AUDIOCFG_BIN_SIZE) + return -EINVAL; + + audio_cfg.if_format = *(buf + index++); + audio_cfg.i2s_entries = *(buf + index++); + audio_cfg.freq = *(buf + index++); + audio_cfg.word_length = *(buf + index++); + audio_cfg.format = *(buf + index++); + audio_cfg.if_mode = *(buf + index++); + audio_cfg.mute = *(buf + index++); + } + + audiocfg(hdev, &audio_cfg); + + return count; +} + +static ssize_t show_plugstatus(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + int index = 0; + struct av8100_status av8100_status; + u8 plstat; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + av8100_status = av8100_status_get(); + plstat = av8100_status.av8100_plugin_status == AV8100_HDMI_PLUGIN; + + if (hdev->sysfs_data.store_as_hextext) { + snprintf(buf + index, 3, "%02x", plstat); + index += 2; + } else + *(buf + index++) = plstat; + + if (hdev->sysfs_data.store_as_hextext) + index++; + + return index; +} + +static ssize_t store_poweronoff(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + bool enable = false; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + if (hdev->sysfs_data.store_as_hextext) { + if ((count != HDMI_POWERONOFF_TEXT_SIZE) && + (count != HDMI_POWERONOFF_TEXT_SIZE + 1)) + return -EINVAL; + if ((*buf == '0') && (*(buf + 1) == '1')) + enable = true; + } else { + if (count != HDMI_POWERONOFF_BIN_SIZE) + return -EINVAL; + if (*buf == 0x01) + enable = true; + } + + if (enable == 0) { + if (av8100_powerdown() != 0) { + dev_err(hdev->dev, "av8100_powerdown FAIL\n"); + return -EINVAL; + } + } else { + if (av8100_powerup() != 0) { + dev_err(hdev->dev, "av8100_powerup FAIL\n"); + return -EINVAL; + } + } + + return count; +} + +static ssize_t show_poweronoff(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + int index = 0; + struct av8100_status status; + u8 power_state; + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + status = av8100_status_get(); + if (status.av8100_state < AV8100_OPMODE_SCAN) + power_state = 0; + else + power_state = 1; + + if (hdev->sysfs_data.store_as_hextext) { + snprintf(buf + index, 3, "%02x", power_state); + index += 3; + } else { + *(buf + index++) = power_state; + } + + return index; +} + +static ssize_t store_evwakeup(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct hdmi_device *hdev = dev_to_hdev(dev); + + if (!hdev) + return -EFAULT; + + dev_dbg(hdev->dev, "%s\n", __func__); + + event_wakeup(hdev); + + return count; +} + +static int hdmi_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int hdmi_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +/* ioctl */ +static long hdmi_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + u8 value = 0; + struct hdmi_register reg; + struct av8100_status status; + u8 aes_status; + struct hdmi_device *hdev = devnr_to_hdev(HDMI_DEVNR_DEFAULT); + + switch (cmd) { + case IOC_PLUG_DETECT_ENABLE: + { + struct plug_detect plug_detect; + + if (copy_from_user(&plug_detect, (void *)arg, + sizeof(struct plug_detect))) + return -EINVAL; + + if (plugdeten(hdev, &plug_detect)) + return -EINVAL; + } + break; + + case IOC_EDID_READ: + { + struct edid_read edid_read; + + if (copy_from_user(&edid_read, (void *)arg, + sizeof(struct edid_read))) + return -EINVAL; + + if (edidread(hdev, &edid_read, &edid_read.data_length, + edid_read.data)) + return -EINVAL; + + if (copy_to_user((void *)arg, (void *)&edid_read, + sizeof(struct edid_read))) { + return -EINVAL; + } + } + break; + + case IOC_CEC_EVENT_ENABLE: + if (copy_from_user(&value, (void *)arg, sizeof(u8))) + return -EINVAL; + + event_enable(hdev, value != 0, + HDMI_EVENT_CEC | HDMI_EVENT_CECTXERR | + HDMI_EVENT_CECTX); + break; + + case IOC_CEC_READ: + { + struct cec_rw cec_read; + + if (cecread(hdev, &cec_read.src, &cec_read.dest, + &cec_read.length, cec_read.data)) + return -EINVAL; + + if (copy_to_user((void *)arg, (void *)&cec_read, + sizeof(struct cec_rw))) { + return -EINVAL; + } + } + break; + + case IOC_CEC_SEND: + { + struct cec_rw cec_send; + + if (copy_from_user(&cec_send, (void *)arg, + sizeof(struct cec_rw))) + return -EINVAL; + + if (cecsend(hdev, cec_send.src, cec_send.dest, cec_send.length, + cec_send.data)) + return -EINVAL; + } + break; + + case IOC_INFOFRAME_SEND: + { + struct info_fr info_fr; + + if (copy_from_user(&info_fr, (void *)arg, + sizeof(struct info_fr))) + return -EINVAL; + + if (infofrsend(hdev, info_fr.type, info_fr.ver, info_fr.crc, + info_fr.length, info_fr.data)) + return -EINVAL; + } + break; + + case IOC_HDCP_EVENT_ENABLE: + if (copy_from_user(&value, (void *)arg, sizeof(u8))) + return -EINVAL; + + event_enable(hdev, value != 0, HDMI_EVENT_HDCP); + break; + + case IOC_HDCP_CHKAESOTP: + if (hdcpchkaesotp(hdev, &value, &aes_status)) + return -EINVAL; + + if (copy_to_user((void *)arg, (void *)&aes_status, + sizeof(u8))) { + return -EINVAL; + } + break; + + case IOC_HDCP_FUSEAES: + { + struct hdcp_fuseaes hdcp_fuseaes; + + if (copy_from_user(&hdcp_fuseaes, (void *)arg, + sizeof(struct hdcp_fuseaes))) + return -EINVAL; + + if (hdcpfuseaes(hdev, hdcp_fuseaes.key, hdcp_fuseaes.crc, + &hdcp_fuseaes.result)) + return -EINVAL; + + if (copy_to_user((void *)arg, (void *)&hdcp_fuseaes, + sizeof(struct hdcp_fuseaes))) { + return -EINVAL; + } + } + break; + + case IOC_HDCP_LOADAES: + { + int block_cnt; + struct hdcp_loadaesone hdcp_loadaesone; + struct hdcp_loadaesall hdcp_loadaesall; + + if (copy_from_user(&hdcp_loadaesall, (void *)arg, + sizeof(struct hdcp_loadaesall))) + return -EINVAL; + + if (hdcpchkaesotp(hdev, &value, &aes_status)) + return -EINVAL; + + if (!aes_status) { + /* AES is not fused */ + hdcp_loadaesone.result = HDMI_AES_NOT_FUSED; + goto ioc_hdcploadaes_err; + } + + /* AES */ + block_cnt = 0; + while (block_cnt < HDMI_HDCP_AES_NR_OF_BLOCKS) { + memcpy(hdcp_loadaesone.key, hdcp_loadaesall.key + + block_cnt * HDMI_HDCP_AES_KEYSIZE, + HDMI_HDCP_AES_KEYSIZE); + + if (hdcploadaes(hdev, + block_cnt + HDMI_HDCP_AES_BLOCK_START, + HDMI_HDCP_AES_KEYSIZE, + hdcp_loadaesone.key, + &hdcp_loadaesone.result, + hdcp_loadaesone.crc32)) + return -EINVAL; + + if (hdcp_loadaesone.result) + return -EINVAL; + + block_cnt++; + } + + /* KSV */ + memset(hdcp_loadaesone.key, 0, HDMI_HDCP_AES_KSVZEROESSIZE); + memcpy(hdcp_loadaesone.key + HDMI_HDCP_AES_KSVZEROESSIZE, + hdcp_loadaesall.ksv, HDMI_HDCP_AES_KSVSIZE); + + if (hdcploadaes(hdev, HDMI_HDCP_KSV_BLOCK, + HDMI_HDCP_AES_KSVSIZE + + HDMI_HDCP_AES_KSVZEROESSIZE, + hdcp_loadaesone.key, + &hdcp_loadaesone.result, + NULL)) + return -EINVAL; + + if (hdcp_loadaesone.result) + return -EINVAL; + + /* CRC32 */ + if (memcmp(hdcp_loadaesall.crc32, hdcp_loadaesone.crc32, + CRC32_SIZE)) { + dev_dbg(hdev->dev, "crc32exp:%02x%02x%02x%02x\n", + hdcp_loadaesall.crc32[0], + hdcp_loadaesall.crc32[1], + hdcp_loadaesall.crc32[2], + hdcp_loadaesall.crc32[3]); + hdcp_loadaesone.result = HDMI_RESULT_CRC_MISMATCH; + goto ioc_hdcploadaes_err; + } + +ioc_hdcploadaes_err: + hdcp_loadaesall.result = hdcp_loadaesone.result; + + if (copy_to_user((void *)arg, (void *)&hdcp_loadaesall, + sizeof(struct hdcp_loadaesall))) { + return -EINVAL; + } + } + break; + + case IOC_HDCP_AUTHENCR_REQ: + { + struct hdcp_authencr hdcp_authencr; + int result = HDMI_RESULT_NOT_OK; + + u8 buf[AUTH_BUF_LEN]; + + if (copy_from_user(&hdcp_authencr, (void *)arg, + sizeof(struct hdcp_authencr))) + return -EINVAL; + + /* Default not OK */ + hdcp_authencr.resp_size = 0; + + if (hdcpchkaesotp(hdev, &value, &aes_status)) { + result = HDMI_AES_NOT_FUSED; + goto hdcp_authencr_end; + } + + if (!aes_status) { + /* AES is not fused */ + result = HDMI_AES_NOT_FUSED; + goto hdcp_authencr_end; + } + + if (hdcpauthencr(hdev, hdcp_authencr.auth_type, + hdcp_authencr.encr_type, + &value, + buf)) { + result = HDMI_RESULT_NOT_OK; + goto hdcp_authencr_end; + } + + if (value > AUTH_BUF_LEN) + value = AUTH_BUF_LEN; + + result = HDMI_RESULT_OK; + hdcp_authencr.resp_size = value; + memcpy(hdcp_authencr.resp, buf, value); + +hdcp_authencr_end: + hdcp_authencr.result = result; + if (copy_to_user((void *)arg, (void *)&hdcp_authencr, + sizeof(struct hdcp_authencr))) + return -EINVAL; + } + break; + + case IOC_HDCP_STATE_GET: + if (av8100_reg_gen_status_r(NULL, NULL, NULL, NULL, NULL, + &value)) + return -EINVAL; + + if (copy_to_user((void *)arg, (void *)&value, + sizeof(u8))) { + return -EINVAL; + } + break; + + case IOC_EVENTS_READ: + value = events_read(hdev); + + if (copy_to_user((void *)arg, (void *)&value, + sizeof(u8))) { + return -EINVAL; + } + + /* Events are read: clear events */ + events_clear(hdev, EVENTS_MASK); + break; + + case IOC_EVENTS_CLEAR: + if (copy_from_user(&value, (void *)arg, sizeof(u8))) + return -EINVAL; + + events_clear(hdev, value); + break; + + case IOC_AUDIO_CFG: + { + struct audio_cfg audio_cfg; + + if (copy_from_user(&audio_cfg, (void *)arg, + sizeof(struct audio_cfg))) + return -EINVAL; + + audiocfg(hdev, &audio_cfg); + } + break; + + case IOC_PLUG_STATUS: + status = av8100_status_get(); + value = status.av8100_plugin_status == AV8100_HDMI_PLUGIN; + + if (copy_to_user((void *)arg, (void *)&value, + sizeof(u8))) { + return -EINVAL; + } + break; + + case IOC_POWERONOFF: + /* Get desired power state on or off */ + if (copy_from_user(&value, (void *)arg, sizeof(u8))) + return -EINVAL; + + if (value == 0) { + if (av8100_powerdown() != 0) { + dev_err(hdev->dev, "av8100_powerdown FAIL\n"); + return -EINVAL; + } + } else { + if (av8100_powerup() != 0) { + dev_err(hdev->dev, "av8100_powerup FAIL\n"); + return -EINVAL; + } + } + break; + + case IOC_EVENT_WAKEUP: + /* Trigger event */ + event_wakeup(hdev); + break; + + case IOC_POWERSTATE: + status = av8100_status_get(); + value = status.av8100_state >= AV8100_OPMODE_SCAN; + + if (copy_to_user((void *)arg, (void *)&value, + sizeof(u8))) { + return -EINVAL; + } + break; + + /* Internal */ + case IOC_HDMI_ENABLE_INTERRUPTS: + av8100_disable_interrupt(); + if (av8100_enable_interrupt() != 0) { + dev_err(hdev->dev, "av8100_ei FAIL\n"); + return -EINVAL; + } + break; + + case IOC_HDMI_DOWNLOAD_FW: + if (av8100_download_firmware(I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100 dl fw FAIL\n"); + return -EINVAL; + } + break; + + case IOC_HDMI_ONOFF: + { + union av8100_configuration config; + + /* Get desired HDMI mode on or off */ + if (copy_from_user(&value, (void *)arg, sizeof(u8))) + return -EFAULT; + + if (av8100_conf_get(AV8100_COMMAND_HDMI, &config) != 0) { + dev_err(hdev->dev, "av8100_conf_get FAIL\n"); + return -EINVAL; + } + if (value == 0) + config.hdmi_format.hdmi_mode = AV8100_HDMI_OFF; + else + config.hdmi_format.hdmi_mode = AV8100_HDMI_ON; + + if (av8100_conf_prep(AV8100_COMMAND_HDMI, &config) != 0) { + dev_err(hdev->dev, "av8100_conf_prep FAIL\n"); + return -EINVAL; + } + if (av8100_conf_w(AV8100_COMMAND_HDMI, NULL, NULL, + I2C_INTERFACE) != 0) { + dev_err(hdev->dev, "av8100_conf_w FAIL\n"); + return -EINVAL; + } + } + break; + + case IOC_HDMI_REGISTER_WRITE: + if (copy_from_user(®, (void *)arg, + sizeof(struct hdmi_register))) { + return -EINVAL; + } + + if (av8100_reg_w(reg.offset, reg.value) != 0) { + dev_err(hdev->dev, "hdmi_register_write FAIL\n"); + return -EINVAL; + } + break; + + case IOC_HDMI_REGISTER_READ: + if (copy_from_user(®, (void *)arg, + sizeof(struct hdmi_register))) { + return -EINVAL; + } + + if (av8100_reg_r(reg.offset, ®.value) != 0) { + dev_err(hdev->dev, "hdmi_register_write FAIL\n"); + return -EINVAL; + } + + if (copy_to_user((void *)arg, (void *)®, + sizeof(struct hdmi_register))) { + return -EINVAL; + } + break; + + case IOC_HDMI_STATUS_GET: + status = av8100_status_get(); + + if (copy_to_user((void *)arg, (void *)&status, + sizeof(struct av8100_status))) { + return -EINVAL; + } + break; + + case IOC_HDMI_CONFIGURATION_WRITE: + { + struct hdmi_command_register command_reg; + + if (copy_from_user(&command_reg, (void *)arg, + sizeof(struct hdmi_command_register)) != 0) { + dev_err(hdev->dev, "IOC_HDMI_CONFIGURATION_WRITE " + "fail 1\n"); + command_reg.return_status = EINVAL; + } else { + command_reg.return_status = 0; + if (av8100_conf_w_raw(command_reg.cmd_id, + command_reg.buf_len, + command_reg.buf, + &(command_reg.buf_len), + command_reg.buf) != 0) { + dev_err(hdev->dev, + "IOC_HDMI_CONFIGURATION_WRITE " + "fail 2\n"); + command_reg.return_status = EINVAL; + } + } + + if (copy_to_user((void *)arg, (void *)&command_reg, + sizeof(struct hdmi_command_register)) != 0) { + return -EINVAL; + } + } + break; + + default: + break; + } + + return 0; +} + +static unsigned int +hdmi_poll(struct file *filp, poll_table *wait) +{ + unsigned int mask = 0; + struct hdmi_device *hdev; + + hdev = devnr_to_hdev(HDMI_DEVNR_DEFAULT); + if (!hdev) + return 0; + + dev_dbg(hdev->dev, "%s\n", __func__); + + poll_wait(filp, &hdev->event_wq , wait); + + LOCK_HDMI_EVENTS; + if (hdev->events_received == true) { + hdev->events_received = false; + mask = POLLIN | POLLRDNORM; + } + UNLOCK_HDMI_EVENTS; + + return mask; +} + +static const struct file_operations hdmi_fops = { + .owner = THIS_MODULE, + .open = hdmi_open, + .release = hdmi_release, + .unlocked_ioctl = hdmi_ioctl, + .poll = hdmi_poll +}; + +/* Event callback function called by hw driver */ +void hdmi_event(enum av8100_hdmi_event ev) +{ + int events_old; + int events_new; + struct hdmi_device *hdev; + struct kobject *kobj; + + hdev = devnr_to_hdev(HDMI_DEVNR_DEFAULT); + if (!hdev) + return; + + dev_dbg(hdev->dev, "hdmi_event %02x\n", ev); + + kobj = &(hdev->dev->kobj); + + LOCK_HDMI_EVENTS; + + events_old = hdev->events; + + /* Set event */ + switch (ev) { + case AV8100_HDMI_EVENT_HDMI_PLUGIN: + hdev->events &= ~HDMI_EVENT_HDMI_PLUGOUT; + hdev->events |= HDMI_EVENT_HDMI_PLUGIN; + break; + + case AV8100_HDMI_EVENT_HDMI_PLUGOUT: + hdev->events &= ~HDMI_EVENT_HDMI_PLUGIN; + hdev->events |= HDMI_EVENT_HDMI_PLUGOUT; + cec_tx_status(hdev, CEC_TX_SET_FREE); + break; + + case AV8100_HDMI_EVENT_CEC: + hdev->events |= HDMI_EVENT_CEC; + break; + + case AV8100_HDMI_EVENT_HDCP: + hdev->events |= HDMI_EVENT_HDCP; + break; + + case AV8100_HDMI_EVENT_CECTXERR: + hdev->events |= HDMI_EVENT_CECTXERR; + cec_tx_status(hdev, CEC_TX_SET_FREE); + break; + + case AV8100_HDMI_EVENT_CECTX: + hdev->events |= HDMI_EVENT_CECTX; + cec_tx_status(hdev, CEC_TX_SET_FREE); + break; + + default: + break; + } + + events_new = hdev->events_mask & hdev->events; + + UNLOCK_HDMI_EVENTS; + + dev_dbg(hdev->dev, "hdmi events:%02x, events_old:%02x mask:%02x\n", + events_new, events_old, hdev->events_mask); + + if (events_new != events_old) { + /* Wake up application waiting for event via call to poll() */ + sysfs_notify(kobj, NULL, SYSFS_EVENT_FILENAME); + + LOCK_HDMI_EVENTS; + hdev->events_received = true; + UNLOCK_HDMI_EVENTS; + + wake_up_interruptible(&hdev->event_wq); + } +} +EXPORT_SYMBOL(hdmi_event); + +int hdmi_device_register(struct hdmi_device *hdev) +{ + hdev->miscdev.minor = MISC_DYNAMIC_MINOR; + hdev->miscdev.name = "hdmi"; + hdev->miscdev.fops = &hdmi_fops; + + if (misc_register(&hdev->miscdev)) { + pr_err("hdmi misc_register failed\n"); + return -EFAULT; + } + + hdev->dev = hdev->miscdev.this_device; + + return 0; +} + +int __init hdmi_init(void) +{ + struct hdmi_device *hdev; + int i; + int ret; + + /* Allocate device data */ + hdev = kzalloc(sizeof(struct hdmi_device), GFP_KERNEL); + if (!hdev) { + pr_err("%s: Alloc failure\n", __func__); + return -ENOMEM; + } + + /* Add to list */ + list_add_tail(&hdev->list, &hdmi_device_list); + + if (hdmi_device_register(hdev)) { + pr_err("%s: Alloc failure\n", __func__); + return -EFAULT; + } + + hdev->devnr = HDMI_DEVNR_DEFAULT; + + /* Default sysfs file format is hextext */ + hdev->sysfs_data.store_as_hextext = true; + + init_waitqueue_head(&hdev->event_wq); + + /* Create sysfs attrs */ + for (i = 0; attr_name(hdmi_sysfs_attrs[i]); i++) { + ret = device_create_file(hdev->dev, &hdmi_sysfs_attrs[i]); + if (ret) + dev_err(hdev->dev, + "Unable to create sysfs attr %s (%d)\n", + hdmi_sysfs_attrs[i].attr.name, ret); + } + + /* Register event callback */ + av8100_hdmi_event_cb_set(hdmi_event); + + return 0; +} +late_initcall(hdmi_init); + +void hdmi_exit(void) +{ + struct hdmi_device *hdev = NULL; + int i; + + if (list_empty(&hdmi_device_list)) + return; + else + hdev = list_entry(hdmi_device_list.next, + struct hdmi_device, list); + + /* Deregister event callback */ + av8100_hdmi_event_cb_set(NULL); + + /* Remove sysfs attrs */ + for (i = 0; attr_name(hdmi_sysfs_attrs[i]); i++) + device_remove_file(hdev->dev, &hdmi_sysfs_attrs[i]); + + misc_deregister(&hdev->miscdev); + + /* Remove from list */ + list_del(&hdev->list); + + /* Free device data */ + kfree(hdev); +} diff --git a/drivers/video/av8100/hdmi_loc.h b/drivers/video/av8100/hdmi_loc.h new file mode 100644 index 00000000000..20314910db9 --- /dev/null +++ b/drivers/video/av8100/hdmi_loc.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * + * Author: Per Persson <per.xb.persson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ +#ifndef __HDMI_LOC__H__ +#define __HDMI_LOC__H__ + +#define EDID_BUF_LEN 128 +#define COMMAND_BUF_LEN 128 +#define AES_KEY_SIZE 16 +#define CRC32_SIZE 4 +#define AUTH_BUF_LEN 126 +#define CECTX_TRY 20 +#define CECTX_WAITTIME 25 + +struct edid_data { + u8 buf_len; + u8 buf[EDID_BUF_LEN]; +}; + +struct authencr { + int result; + u8 buf_len; + u8 buf[AUTH_BUF_LEN]; +}; + +struct hdmi_register { + unsigned char value; + unsigned char offset; +}; + +struct hdcp_loadaesone { + u8 key[AES_KEY_SIZE]; + u8 result; + u8 crc32[CRC32_SIZE]; +}; + +struct hdmi_sysfs_data { + bool store_as_hextext; + struct plug_detect plug_detect; + bool enable_cec_event; + struct edid_data edid_data; + struct cec_rw cec_read; + bool fuse_result; + int loadaes_result; + struct authencr authencr; +}; + +struct hdmi_command_register { + unsigned char cmd_id; /* input */ + unsigned char buf_len; /* input, output */ + unsigned char buf[COMMAND_BUF_LEN]; /* input, output */ + unsigned char return_status; /* output */ +}; + +enum cec_tx_status_action { + CEC_TX_SET_FREE, + CEC_TX_SET_BUSY, + CEC_TX_CHECK +}; + +/* Internal */ +#define IOC_HDMI_ENABLE_INTERRUPTS _IOWR(HDMI_IOC_MAGIC, 32, int) +#define IOC_HDMI_DOWNLOAD_FW _IOWR(HDMI_IOC_MAGIC, 33, int) +#define IOC_HDMI_ONOFF _IOWR(HDMI_IOC_MAGIC, 34, int) +#define IOC_HDMI_REGISTER_WRITE _IOWR(HDMI_IOC_MAGIC, 35, int) +#define IOC_HDMI_REGISTER_READ _IOWR(HDMI_IOC_MAGIC, 36, int) +#define IOC_HDMI_STATUS_GET _IOWR(HDMI_IOC_MAGIC, 37, int) +#define IOC_HDMI_CONFIGURATION_WRITE _IOWR(HDMI_IOC_MAGIC, 38, int) + +#endif /* __HDMI_LOC__H__ */ diff --git a/drivers/video/b2r2/Kconfig b/drivers/video/b2r2/Kconfig new file mode 100644 index 00000000000..8cc81876de7 --- /dev/null +++ b/drivers/video/b2r2/Kconfig @@ -0,0 +1,134 @@ +config FB_B2R2 + tristate "B2R2 engine support" + default n + help + B2R2 engine does various bit-blitting operations,post-processor operations + and various compositions. + +config B2R2_PLUG_CONF + bool "B2R2 bus plug configuration" + depends on FB_B2R2 + default n + help + Configures how B2R2 access the memory bus. Enabling this will increase + the performance of B2R2 at the cost of using the bus more heavily. + + If this is set to 'n', the hardware defaults will be used. + +choice + prompt "Opcode size" + depends on B2R2_PLUG_CONF + default B2R2_OPSIZE_64 + + config B2R2_OPSIZE_8 + bool "8 bytes" + config B2R2_OPSIZE_16 + bool "16 bytes" + config B2R2_OPSIZE_32 + bool "32 bytes" + config B2R2_OPSIZE_64 + bool "64 bytes" + +endchoice + +choice + prompt "Chunk size" + depends on B2R2_PLUG_CONF + default B2R2_CHSIZE_128 + + config B2R2_CHSIZE_1 + bool "1 op" + config B2R2_CHSIZE_2 + bool "2 ops" + config B2R2_CHSIZE_4 + bool "4 ops" + config B2R2_CHSIZE_8 + bool "8 ops" + config B2R2_CHSIZE_16 + bool "16 ops" + config B2R2_CHSIZE_32 + bool "32 ops" + config B2R2_CHSIZE_64 + bool "64 ops" + config B2R2_CHSIZE_128 + bool "128 ops" +endchoice + +choice + prompt "Message size" + depends on B2R2_PLUG_CONF + default B2R2_MGSIZE_128 + + config B2R2_MGSIZE_1 + bool "1 chunk" + config B2R2_MGSIZE_2 + bool "2 chunks" + config B2R2_MGSIZE_4 + bool "4 chunks" + config B2R2_MGSIZE_8 + bool "8 s" + config B2R2_MGSIZE_16 + bool "16 chunks" + config B2R2_MGSIZE_32 + bool "32 chunks" + config B2R2_MGSIZE_64 + bool "64 chunks" + config B2R2_MGSIZE_128 + bool "128 chunks" +endchoice + +choice + prompt "Page size" + depends on B2R2_PLUG_CONF + default B2R2_PGSIZE_256 + + config B2R2_PGSIZE_64 + bool "64 bytes" + config B2R2_PGSIZE_128 + bool "128 bytes" + config B2R2_PGSIZE_256 + bool "256 bytes" +endchoice + +config B2R2_DEBUG + bool "B2R2 debugging" + default n + depends on FB_B2R2 + help + Enable debugging features for the B2R2 driver. + +config B2R2_PROFILER + tristate "B2R2 profiler" + default n + depends on FB_B2R2 + help + Enables the profiler for the B2R2 driver. + + It is recommended to build this as a module, since the configuration + of filters etc. is done at load time. + +config B2R2_GENERIC + bool "B2R2 generic path" + default y + depends on FB_B2R2 + help + Enables support for the generic path in the B2R2 driver. This path should + be used when there is no optimized implementation for a request. + +choice + prompt "Generic usage mode" + depends on B2R2_GENERIC + default B2R2_GENERIC_FALLBACK + + config B2R2_GENERIC_FALLBACK + bool "Fallback" + help + The optimized path will be used for all supported operations, and the + generic path will be used as a fallback for the ones not implemented. + + config B2R2_GENERIC_ONLY + bool "Always" + help + The generic path will be used for all operations. + +endchoice diff --git a/drivers/video/b2r2/Makefile b/drivers/video/b2r2/Makefile new file mode 100644 index 00000000000..0150ad6f761 --- /dev/null +++ b/drivers/video/b2r2/Makefile @@ -0,0 +1,15 @@ +# Make file for compiling and loadable module B2R2 + +obj-$(CONFIG_FB_B2R2) += b2r2.o + +b2r2-objs = b2r2_blt_main.o b2r2_core.o b2r2_mem_alloc.o b2r2_generic.o b2r2_node_gen.o b2r2_node_split.o b2r2_profiler_socket.o b2r2_timing.o b2r2_filters.o b2r2_utils.o b2r2_input_validation.o + +ifdef CONFIG_B2R2_DEBUG +b2r2-objs += b2r2_debug.o +endif + +ifeq ($(CONFIG_FB_B2R2),m) +obj-y += b2r2_kernel_if.o +endif + +obj-$(CONFIG_B2R2_PROFILER) += b2r2_profiler/ diff --git a/drivers/video/b2r2/b2r2_blt_main.c b/drivers/video/b2r2/b2r2_blt_main.c new file mode 100644 index 00000000000..f79bfaee9ab --- /dev/null +++ b/drivers/video/b2r2/b2r2_blt_main.c @@ -0,0 +1,3363 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 Blitter module + * + * Author: Robert Fekete <robert.fekete@stericsson.com> + * Author: Paul Wannback + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/poll.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/miscdevice.h> +#include <linux/list.h> +#ifdef CONFIG_ANDROID_PMEM +#include <linux/android_pmem.h> +#endif +#include <linux/fb.h> +#include <linux/uaccess.h> +#ifdef CONFIG_DEBUG_FS +#include <linux/debugfs.h> +#endif +#include <asm/cacheflush.h> +#include <linux/smp.h> +#include <linux/dma-mapping.h> +#include <linux/sched.h> +#include <linux/err.h> +#include <linux/hwmem.h> + +#include "b2r2_internal.h" +#include "b2r2_node_split.h" +#include "b2r2_generic.h" +#include "b2r2_mem_alloc.h" +#include "b2r2_profiler_socket.h" +#include "b2r2_timing.h" +#include "b2r2_debug.h" +#include "b2r2_utils.h" +#include "b2r2_input_validation.h" +#include "b2r2_core.h" +#include "b2r2_filters.h" + +#define B2R2_HEAP_SIZE (4 * PAGE_SIZE) +#define MAX_TMP_BUF_SIZE (128 * PAGE_SIZE) + +/* + * TODO: + * Implementation of query cap + * Support for user space virtual pointer to physically consecutive memory + * Support for user space virtual pointer to physically scattered memory + * Callback reads lagging behind in blt_api_stress app + * Store smaller items in the report list instead of the whole request + * Support read of many report records at once. + */ + +/** + * b2r2_blt_dev - Our device(s), /dev/b2r2_blt + */ +static struct b2r2_control *b2r2_ctl[B2R2_MAX_NBR_DEVICES]; + +/* Debug file system support */ +#ifdef CONFIG_DEBUG_FS +static int sprintf_req(struct b2r2_blt_request *request, char *buf, int size); +#endif + +/* Local functions */ +static void inc_stat(struct b2r2_control *cont, unsigned long *stat); +static void dec_stat(struct b2r2_control *cont, unsigned long *stat); +static int b2r2_blt_synch(struct b2r2_blt_instance *instance, + int request_id); +static int b2r2_blt_query_cap(struct b2r2_blt_instance *instance, + struct b2r2_blt_query_cap *query_cap); + +#ifndef CONFIG_B2R2_GENERIC_ONLY +static int b2r2_blt(struct b2r2_blt_instance *instance, + struct b2r2_blt_request *request); + +static void job_callback(struct b2r2_core_job *job); +static void job_release(struct b2r2_core_job *job); +static int job_acquire_resources(struct b2r2_core_job *job, bool atomic); +static void job_release_resources(struct b2r2_core_job *job, bool atomic); +#endif + +#ifdef CONFIG_B2R2_GENERIC +static int b2r2_generic_blt(struct b2r2_blt_instance *instance, + struct b2r2_blt_request *request); + +static void job_callback_gen(struct b2r2_core_job *job); +static void job_release_gen(struct b2r2_core_job *job); +static int job_acquire_resources_gen(struct b2r2_core_job *job, bool atomic); +static void job_release_resources_gen(struct b2r2_core_job *job, bool atomic); +static void tile_job_callback_gen(struct b2r2_core_job *job); +static void tile_job_release_gen(struct b2r2_core_job *job); +#endif + + +static int resolve_buf(struct b2r2_control *cont, + struct b2r2_blt_img *img, struct b2r2_blt_rect *rect_2b_used, + bool is_dst, struct b2r2_resolved_buf *resolved); +static void unresolve_buf(struct b2r2_control *cont, + struct b2r2_blt_buf *buf, struct b2r2_resolved_buf *resolved); +static void sync_buf(struct b2r2_control *cont, struct b2r2_blt_img *img, + struct b2r2_resolved_buf *resolved, bool is_dst, + struct b2r2_blt_rect *rect); +static bool is_report_list_empty(struct b2r2_blt_instance *instance); +static bool is_synching(struct b2r2_blt_instance *instance); +static void get_actual_dst_rect(struct b2r2_blt_req *req, + struct b2r2_blt_rect *actual_dst_rect); +static void set_up_hwmem_region(struct b2r2_control *cont, + struct b2r2_blt_img *img, struct b2r2_blt_rect *rect, + struct hwmem_region *region); +static int resolve_hwmem(struct b2r2_control *cont, struct b2r2_blt_img *img, + struct b2r2_blt_rect *rect_2b_used, bool is_dst, + struct b2r2_resolved_buf *resolved_buf); +static void unresolve_hwmem(struct b2r2_resolved_buf *resolved_buf); + +/** + * struct sync_args - Data for clean/flush + * + * @start: Virtual start address + * @end: Virtual end address + */ +struct sync_args { + unsigned long start; + unsigned long end; +}; +/** + * flush_l1_cache_range_curr_cpu() - Cleans and invalidates L1 cache on the + * current CPU + * + * @arg: Pointer to sync_args structure + */ +static inline void flush_l1_cache_range_curr_cpu(void *arg) +{ + struct sync_args *sa = (struct sync_args *)arg; + + dmac_flush_range((void *)sa->start, (void *)sa->end); +} + +#ifdef CONFIG_SMP +/** + * inv_l1_cache_range_all_cpus() - Cleans and invalidates L1 cache on all CPU:s + * + * @sa: Pointer to sync_args structure + */ +static void flush_l1_cache_range_all_cpus(struct sync_args *sa) +{ + on_each_cpu(flush_l1_cache_range_curr_cpu, sa, 1); +} +#endif + +/** + * clean_l1_cache_range_curr_cpu() - Cleans L1 cache on current CPU + * + * Ensures that data is written out from the CPU:s L1 cache, + * it will still be in the cache. + * + * @arg: Pointer to sync_args structure + */ +static inline void clean_l1_cache_range_curr_cpu(void *arg) +{ + struct sync_args *sa = (struct sync_args *)arg; + + dmac_map_area((void *)sa->start, + (void *)sa->end - (void *)sa->start, + DMA_TO_DEVICE); +} + +#ifdef CONFIG_SMP +/** + * clean_l1_cache_range_all_cpus() - Cleans L1 cache on all CPU:s + * + * Ensures that data is written out from all CPU:s L1 cache, + * it will still be in the cache. + * + * @sa: Pointer to sync_args structure + */ +static void clean_l1_cache_range_all_cpus(struct sync_args *sa) +{ + on_each_cpu(clean_l1_cache_range_curr_cpu, sa, 1); +} +#endif + +/** + * b2r2_blt_open - Implements file open on the b2r2_blt device + * + * @inode: File system inode + * @filp: File pointer + * + * A B2R2 BLT instance is created and stored in the file structure. + */ +static int b2r2_blt_open(struct inode *inode, struct file *filp) +{ + int ret = 0; + struct b2r2_blt_instance *instance; + struct b2r2_control *cont = filp->private_data; + + b2r2_log_info(cont->dev, "%s\n", __func__); + + inc_stat(cont, &cont->stat_n_in_open); + + /* Allocate and initialize the instance */ + instance = (struct b2r2_blt_instance *) + kmalloc(sizeof(*instance), GFP_KERNEL); + if (!instance) { + b2r2_log_err(cont->dev, "%s: Failed to alloc\n", __func__); + goto instance_alloc_failed; + } + memset(instance, 0, sizeof(*instance)); + INIT_LIST_HEAD(&instance->report_list); + mutex_init(&instance->lock); + init_waitqueue_head(&instance->report_list_waitq); + init_waitqueue_head(&instance->synch_done_waitq); + instance->control = cont; + + /* + * Remember the instance so that we can retrieve it in + * other functions + */ + filp->private_data = instance; + goto out; + +instance_alloc_failed: +out: + dec_stat(cont, &cont->stat_n_in_open); + + return ret; +} + +/** + * b2r2_blt_release - Implements last close on an instance of + * the b2r2_blt device + * + * @inode: File system inode + * @filp: File pointer + * + * All active jobs are finished or cancelled and allocated data + * is released. + */ +static int b2r2_blt_release(struct inode *inode, struct file *filp) +{ + int ret; + struct b2r2_blt_instance *instance = + (struct b2r2_blt_instance *) filp->private_data; + struct b2r2_control *cont = instance->control; + + b2r2_log_info(cont->dev, "%s\n", __func__); + + inc_stat(cont, &cont->stat_n_in_release); + + /* Finish all outstanding requests */ + ret = b2r2_blt_synch(instance, 0); + if (ret < 0) + b2r2_log_warn(cont->dev, "%s: b2r2_blt_sync failed with %d\n", + __func__, ret); + + /* Now cancel any remaining outstanding request */ + if (instance->no_of_active_requests) { + struct b2r2_core_job *job; + + b2r2_log_warn(cont->dev, "%s: %d active requests\n", __func__, + instance->no_of_active_requests); + + /* Find and cancel all jobs belonging to us */ + job = b2r2_core_job_find_first_with_tag(cont, + (int) instance); + while (job) { + b2r2_core_job_cancel(job); + /* Matches addref in b2r2_core_job_find... */ + b2r2_core_job_release(job, __func__); + job = b2r2_core_job_find_first_with_tag(cont, + (int) instance); + } + + b2r2_log_warn(cont->dev, "%s: %d active requests after " + "cancel\n", __func__, instance->no_of_active_requests); + } + + /* Release jobs in report list */ + mutex_lock(&instance->lock); + while (!list_empty(&instance->report_list)) { + struct b2r2_blt_request *request = list_first_entry( + &instance->report_list, + struct b2r2_blt_request, + list); + list_del_init(&request->list); + mutex_unlock(&instance->lock); + /* + * This release matches the addref when the job was put into + * the report list + */ + b2r2_core_job_release(&request->job, __func__); + mutex_lock(&instance->lock); + } + mutex_unlock(&instance->lock); + + /* Release our instance */ + kfree(instance); + + dec_stat(cont, &cont->stat_n_in_release); + + return 0; +} + +/** + * b2r2_blt_ioctl - This routine implements b2r2_blt ioctl interface + * + * @file: file pointer. + * @cmd :ioctl command. + * @arg: input argument for ioctl. + * + * Returns 0 if OK else negative error code + */ +static long b2r2_blt_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + struct b2r2_blt_instance *instance = + (struct b2r2_blt_instance *) file->private_data; + struct b2r2_control *cont = instance->control; + + /** Process actual ioctl */ + b2r2_log_info(cont->dev, "%s\n", __func__); + + /* Get the instance from the file structure */ + switch (cmd) { + case B2R2_BLT_IOC: { + /* This is the "blit" command */ + + /* arg is user pointer to struct b2r2_blt_request */ + struct b2r2_blt_request *request = + kmalloc(sizeof(*request), GFP_KERNEL); + if (!request) { + b2r2_log_err(cont->dev, "%s: Failed to alloc mem\n", + __func__); + return -ENOMEM; + } + + /* Initialize the structure */ + memset(request, 0, sizeof(*request)); + INIT_LIST_HEAD(&request->list); + request->instance = instance; + + /* + * The user request is a sub structure of the + * kernel request structure. + */ + + /* Get the user data */ + if (copy_from_user(&request->user_req, (void *)arg, + sizeof(request->user_req))) { + b2r2_log_err(cont->dev, "%s: copy_from_user failed\n", + __func__); + kfree(request); + return -EFAULT; + } + + if (!b2r2_validate_user_req(cont, &request->user_req)) { + kfree(request); + return -EINVAL; + } + + request->profile = is_profiler_registered_approx(); + + /* + * If the user specified a color look-up table, + * make a copy that the HW can use. + */ + if ((request->user_req.flags & + B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) != 0) { + request->clut = dma_alloc_coherent(cont->dev, + CLUT_SIZE, &(request->clut_phys_addr), + GFP_DMA | GFP_KERNEL); + if (request->clut == NULL) { + b2r2_log_err(cont->dev, "%s CLUT allocation " + "failed.\n", __func__); + kfree(request); + return -ENOMEM; + } + + if (copy_from_user(request->clut, + request->user_req.clut, CLUT_SIZE)) { + b2r2_log_err(cont->dev, "%s: CLUT " + "copy_from_user failed\n", + __func__); + dma_free_coherent(cont->dev, CLUT_SIZE, + request->clut, + request->clut_phys_addr); + request->clut = NULL; + request->clut_phys_addr = 0; + kfree(request); + return -EFAULT; + } + } + + /* Perform the blit */ + +#ifdef CONFIG_B2R2_GENERIC_ONLY + /* Use the generic path for all operations */ + ret = b2r2_generic_blt(instance, request); +#else + /* Use the optimized path */ + ret = b2r2_blt(instance, request); +#endif + +#ifdef CONFIG_B2R2_GENERIC_FALLBACK + /* Fall back to generic path if operation was not supported */ + if (ret == -ENOSYS) { + struct b2r2_blt_request *request_gen; + + if (request->user_req.flags & B2R2_BLT_FLAG_BG_BLEND) { + /* No support for BG BLEND in generic + * implementation yet */ + b2r2_log_warn(cont->dev, "%s: Unsupported: " + "Background blend in b2r2_generic_blt\n", + __func__); + return ret; + } + + b2r2_log_info(cont->dev, + "b2r2_blt=%d Going generic.\n", ret); + request_gen = kmalloc(sizeof(*request_gen), GFP_KERNEL); + if (!request_gen) { + b2r2_log_err(cont->dev, + "%s: Failed to alloc mem for " + "request_gen\n", __func__); + return -ENOMEM; + } + + /* Initialize the structure */ + memset(request_gen, 0, sizeof(*request_gen)); + INIT_LIST_HEAD(&request_gen->list); + request_gen->instance = instance; + + /* + * The user request is a sub structure of the + * kernel request structure. + */ + + /* Get the user data */ + if (copy_from_user(&request_gen->user_req, (void *)arg, + sizeof(request_gen->user_req))) { + b2r2_log_err(cont->dev, "%s: copy_from_user " + "failed\n", __func__); + kfree(request_gen); + return -EFAULT; + } + + /* + * If the user specified a color look-up table, + * make a copy that the HW can use. + */ + if ((request_gen->user_req.flags & + B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) + != 0) { + request_gen->clut = dma_alloc_coherent( + cont->dev, CLUT_SIZE, + &(request_gen->clut_phys_addr), + GFP_DMA | GFP_KERNEL); + if (request_gen->clut == NULL) { + b2r2_log_err(cont->dev, "%s CLUT " + "allocation failed.\n", + __func__); + kfree(request_gen); + return -ENOMEM; + } + + if (copy_from_user(request_gen->clut, + request_gen->user_req.clut, + CLUT_SIZE)) { + b2r2_log_err(cont->dev, "%s: CLUT" + " copy_from_user failed\n", + __func__); + dma_free_coherent(cont->dev, CLUT_SIZE, + request_gen->clut, + request_gen->clut_phys_addr); + request_gen->clut = NULL; + request_gen->clut_phys_addr = 0; + kfree(request_gen); + return -EFAULT; + } + } + + request_gen->profile = is_profiler_registered_approx(); + + ret = b2r2_generic_blt(instance, request_gen); + b2r2_log_info(cont->dev, "\nb2r2_generic_blt=%d " + "Generic done.\n", ret); + } +#endif /* CONFIG_B2R2_GENERIC_FALLBACK */ + + break; + } + + case B2R2_BLT_SYNCH_IOC: + /* arg is request_id */ + ret = b2r2_blt_synch(instance, (int) arg); + break; + + case B2R2_BLT_QUERY_CAP_IOC: + { + /* Arg is struct b2r2_blt_query_cap */ + struct b2r2_blt_query_cap query_cap; + + /* Get the user data */ + if (copy_from_user(&query_cap, (void *)arg, + sizeof(query_cap))) { + b2r2_log_err(cont->dev, "%s: copy_from_user failed\n", + __func__); + return -EFAULT; + } + + /* Fill in our capabilities */ + ret = b2r2_blt_query_cap(instance, &query_cap); + + /* Return data to user */ + if (copy_to_user((void *)arg, &query_cap, + sizeof(query_cap))) { + b2r2_log_err(cont->dev, "%s: copy_to_user failed\n", + __func__); + return -EFAULT; + } + break; + } + + default: + /* Unknown command */ + b2r2_log_err(cont->dev, "%s: Unknown cmd %d\n", __func__, cmd); + ret = -EINVAL; + break; + + } + + if (ret < 0) + b2r2_log_err(cont->dev, "EC %d OK!\n", -ret); + + return ret; +} + +/** + * b2r2_blt_poll - Support for user-space poll, select & epoll. + * Used for user-space callback + * + * @filp: File to poll on + * @wait: Poll table to wait on + * + * This function checks if there are anything to read + */ +static unsigned b2r2_blt_poll(struct file *filp, poll_table *wait) +{ + struct b2r2_blt_instance *instance = + (struct b2r2_blt_instance *) filp->private_data; + unsigned int mask = 0; +#ifdef CONFIG_B2R2_DEBUG + struct b2r2_control *cont = instance->control; +#endif + + b2r2_log_info(cont->dev, "%s\n", __func__); + + poll_wait(filp, &instance->report_list_waitq, wait); + mutex_lock(&instance->lock); + if (!list_empty(&instance->report_list)) + mask |= POLLIN | POLLRDNORM; + mutex_unlock(&instance->lock); + + return mask; +} + +/** + * b2r2_blt_read - Read report data, user for user-space callback + * + * @filp: File pointer + * @buf: User space buffer + * @count: Number of bytes to read + * @f_pos: File position + * + * Returns number of bytes read or negative error code + */ +static ssize_t b2r2_blt_read(struct file *filp, char __user *buf, size_t count, + loff_t *f_pos) +{ + int ret = 0; + struct b2r2_blt_request *request = NULL; + struct b2r2_blt_report report; + struct b2r2_blt_instance *instance = + (struct b2r2_blt_instance *) filp->private_data; +#ifdef CONFIG_B2R2_DEBUG + struct b2r2_control *cont = instance->control; +#endif + + b2r2_log_info(cont->dev, "%s\n", __func__); + + /* + * We return only complete report records, one at a time. + * Might be more efficient to support read of many. + */ + count = (count / sizeof(struct b2r2_blt_report)) * + sizeof(struct b2r2_blt_report); + if (count > sizeof(struct b2r2_blt_report)) + count = sizeof(struct b2r2_blt_report); + if (count == 0) + return count; + + /* + * Loop and wait here until we have anything to return or + * until interrupted + */ + mutex_lock(&instance->lock); + while (list_empty(&instance->report_list)) { + mutex_unlock(&instance->lock); + + /* Return if non blocking read */ + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + + b2r2_log_info(cont->dev, "%s - Going to sleep\n", __func__); + if (wait_event_interruptible( + instance->report_list_waitq, + !is_report_list_empty(instance))) + /* signal: tell the fs layer to handle it */ + return -ERESTARTSYS; + + /* Otherwise loop, but first reaquire the lock */ + mutex_lock(&instance->lock); + } + + if (!list_empty(&instance->report_list)) + request = list_first_entry( + &instance->report_list, struct b2r2_blt_request, list); + + if (request) { + /* Remove from list to avoid reading twice */ + list_del_init(&request->list); + + report.request_id = request->request_id; + report.report1 = request->user_req.report1; + report.report2 = request->user_req.report2; + report.usec_elapsed = 0; /* TBD */ + + mutex_unlock(&instance->lock); + if (copy_to_user(buf, &report, sizeof(report))) + ret = -EFAULT; + mutex_lock(&instance->lock); + + if (ret < 0) { + /* copy to user failed, re-insert into list */ + list_add(&request->list, + &request->instance->report_list); + request = NULL; + } + } + mutex_unlock(&instance->lock); + + if (request) + /* + * Release matching the addref when the job was put into + * the report list + */ + b2r2_core_job_release(&request->job, __func__); + + return count; +} + +/** + * b2r2_blt_fops - File operations for b2r2_blt + */ +static const struct file_operations b2r2_blt_fops = { + .owner = THIS_MODULE, + .open = b2r2_blt_open, + .release = b2r2_blt_release, + .unlocked_ioctl = b2r2_blt_ioctl, + .poll = b2r2_blt_poll, + .read = b2r2_blt_read, +}; + +#ifndef CONFIG_B2R2_GENERIC_ONLY +/** + * b2r2_blt - Implementation of the B2R2 blit request + * + * @instance: The B2R2 BLT instance + * @request; The request to perform + */ +static int b2r2_blt(struct b2r2_blt_instance *instance, + struct b2r2_blt_request *request) +{ + int ret = 0; + struct b2r2_blt_rect actual_dst_rect; + int request_id = 0; + struct b2r2_node *last_node = request->first_node; + int node_count; + struct b2r2_control *cont = instance->control; + + u32 thread_runtime_at_start = 0; + + if (request->profile) { + request->start_time_nsec = b2r2_get_curr_nsec(); + thread_runtime_at_start = (u32)task_sched_runtime(current); + } + + b2r2_log_info(cont->dev, "%s\n", __func__); + + inc_stat(cont, &cont->stat_n_in_blt); + + /* Debug prints of incoming request */ + b2r2_log_info(cont->dev, + "src.fmt=%#010x src.buf={%d,%d,%d} " + "src.w,h={%d,%d} src.rect={%d,%d,%d,%d}\n", + request->user_req.src_img.fmt, + request->user_req.src_img.buf.type, + request->user_req.src_img.buf.fd, + request->user_req.src_img.buf.offset, + request->user_req.src_img.width, + request->user_req.src_img.height, + request->user_req.src_rect.x, + request->user_req.src_rect.y, + request->user_req.src_rect.width, + request->user_req.src_rect.height); + + if (request->user_req.flags & B2R2_BLT_FLAG_BG_BLEND) + b2r2_log_info(cont->dev, + "bg.fmt=%#010x bg.buf={%d,%d,%d} " + "bg.w,h={%d,%d} bg.rect={%d,%d,%d,%d}\n", + request->user_req.bg_img.fmt, + request->user_req.bg_img.buf.type, + request->user_req.bg_img.buf.fd, + request->user_req.bg_img.buf.offset, + request->user_req.bg_img.width, + request->user_req.bg_img.height, + request->user_req.bg_rect.x, + request->user_req.bg_rect.y, + request->user_req.bg_rect.width, + request->user_req.bg_rect.height); + + b2r2_log_info(cont->dev, + "dst.fmt=%#010x dst.buf={%d,%d,%d} " + "dst.w,h={%d,%d} dst.rect={%d,%d,%d,%d}\n", + request->user_req.dst_img.fmt, + request->user_req.dst_img.buf.type, + request->user_req.dst_img.buf.fd, + request->user_req.dst_img.buf.offset, + request->user_req.dst_img.width, + request->user_req.dst_img.height, + request->user_req.dst_rect.x, + request->user_req.dst_rect.y, + request->user_req.dst_rect.width, + request->user_req.dst_rect.height); + + inc_stat(cont, &cont->stat_n_in_blt_synch); + + /* Wait here if synch is ongoing */ + ret = wait_event_interruptible(instance->synch_done_waitq, + !is_synching(instance)); + if (ret) { + b2r2_log_warn(cont->dev, "%s: Sync wait interrupted, %d\n", + __func__, ret); + ret = -EAGAIN; + dec_stat(cont, &cont->stat_n_in_blt_synch); + goto synch_interrupted; + } + + dec_stat(cont, &cont->stat_n_in_blt_synch); + + /* Resolve the buffers */ + + /* Source buffer */ + ret = resolve_buf(cont, &request->user_req.src_img, + &request->user_req.src_rect, + false, &request->src_resolved); + if (ret < 0) { + b2r2_log_warn(cont->dev, "%s: Resolve src buf failed, %d\n", + __func__, ret); + ret = -EAGAIN; + goto resolve_src_buf_failed; + } + + /* Background buffer */ + if (request->user_req.flags & B2R2_BLT_FLAG_BG_BLEND) { + ret = resolve_buf(cont, &request->user_req.bg_img, + &request->user_req.bg_rect, + false, &request->bg_resolved); + if (ret < 0) { + b2r2_log_warn(cont->dev, "%s: Resolve bg buf failed," + " %d\n", __func__, ret); + ret = -EAGAIN; + goto resolve_bg_buf_failed; + } + } + + /* Source mask buffer */ + ret = resolve_buf(cont, &request->user_req.src_mask, + &request->user_req.src_rect, false, + &request->src_mask_resolved); + if (ret < 0) { + b2r2_log_warn(cont->dev, "%s: Resolve src mask buf failed," + " %d\n", __func__, ret); + ret = -EAGAIN; + goto resolve_src_mask_buf_failed; + } + + /* Destination buffer */ + get_actual_dst_rect(&request->user_req, &actual_dst_rect); + ret = resolve_buf(cont, &request->user_req.dst_img, &actual_dst_rect, + true, &request->dst_resolved); + if (ret < 0) { + b2r2_log_warn(cont->dev, "%s: Resolve dst buf failed, %d\n", + __func__, ret); + ret = -EAGAIN; + goto resolve_dst_buf_failed; + } + + /* Debug prints of resolved buffers */ + b2r2_log_info(cont->dev, "src.rbuf={%X,%p,%d} {%p,%X,%X,%d}\n", + request->src_resolved.physical_address, + request->src_resolved.virtual_address, + request->src_resolved.is_pmem, + request->src_resolved.filep, + request->src_resolved.file_physical_start, + request->src_resolved.file_virtual_start, + request->src_resolved.file_len); + + if (request->user_req.flags & B2R2_BLT_FLAG_BG_BLEND) + b2r2_log_info(cont->dev, "bg.rbuf={%X,%p,%d} {%p,%X,%X,%d}\n", + request->bg_resolved.physical_address, + request->bg_resolved.virtual_address, + request->bg_resolved.is_pmem, + request->bg_resolved.filep, + request->bg_resolved.file_physical_start, + request->bg_resolved.file_virtual_start, + request->bg_resolved.file_len); + + b2r2_log_info(cont->dev, "dst.rbuf={%X,%p,%d} {%p,%X,%X,%d}\n", + request->dst_resolved.physical_address, + request->dst_resolved.virtual_address, + request->dst_resolved.is_pmem, + request->dst_resolved.filep, + request->dst_resolved.file_physical_start, + request->dst_resolved.file_virtual_start, + request->dst_resolved.file_len); + + /* Calculate the number of nodes (and resources) needed for this job */ + ret = b2r2_node_split_analyze(request, MAX_TMP_BUF_SIZE, &node_count, + &request->bufs, &request->buf_count, + &request->node_split_job); + if (ret == -ENOSYS) { + /* There was no optimized path for this request */ + b2r2_log_info(cont->dev, "%s: No optimized path for request\n", + __func__); + goto no_optimized_path; + + } else if (ret < 0) { + b2r2_log_warn(cont->dev, "%s: Failed to analyze request," + " ret = %d\n", __func__, ret); +#ifdef CONFIG_DEBUG_FS + { + /* Failed, dump job to dmesg */ + char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL); + + b2r2_log_info(cont->dev, "%s: Analyze failed for:\n", + __func__); + if (Buf != NULL) { + sprintf_req(request, Buf, sizeof(char) * 4096); + b2r2_log_info(cont->dev, "%s", Buf); + kfree(Buf); + } else { + b2r2_log_info(cont->dev, "Unable to print the" + " request. Message buffer" + " allocation failed.\n"); + } + } +#endif + goto generate_nodes_failed; + } + + /* Allocate the nodes needed */ +#ifdef B2R2_USE_NODE_GEN + request->first_node = b2r2_blt_alloc_nodes(cont, + node_count); + if (request->first_node == NULL) { + b2r2_log_warn(cont->dev, "%s: Failed to allocate nodes," + " ret = %d\n", __func__, ret); + goto generate_nodes_failed; + } +#else + ret = b2r2_node_alloc(cont, node_count, &(request->first_node)); + if (ret < 0 || request->first_node == NULL) { + b2r2_log_warn(cont->dev, + "%s: Failed to allocate nodes, ret = %d\n", + __func__, ret); + goto generate_nodes_failed; + } +#endif + + /* Build the B2R2 node list */ + ret = b2r2_node_split_configure(cont, &request->node_split_job, + request->first_node); + + if (ret < 0) { + b2r2_log_warn(cont->dev, "%s:" + " Failed to perform node split, ret = %d\n", + __func__, ret); + goto generate_nodes_failed; + } + + /* Exit here if dry run */ + if (request->user_req.flags & B2R2_BLT_FLAG_DRY_RUN) + goto exit_dry_run; + + /* Configure the request */ + last_node = request->first_node; + while (last_node && last_node->next) + last_node = last_node->next; + + request->job.tag = (int) instance; + request->job.prio = request->user_req.prio; + request->job.first_node_address = + request->first_node->physical_address; + request->job.last_node_address = + last_node->physical_address; + request->job.callback = job_callback; + request->job.release = job_release; + request->job.acquire_resources = job_acquire_resources; + request->job.release_resources = job_release_resources; + + /* Synchronize memory occupied by the buffers */ + + /* Source buffer */ + if (!(request->user_req.flags & + B2R2_BLT_FLAG_SRC_NO_CACHE_FLUSH) && + (request->user_req.src_img.buf.type != + B2R2_BLT_PTR_PHYSICAL) && + !b2r2_is_mb_fmt(request->user_req.src_img.fmt)) + /* MB formats are never touched by SW */ + sync_buf(cont, &request->user_req.src_img, + &request->src_resolved, false, + &request->user_req.src_rect); + + /* Background buffer */ + if ((request->user_req.flags & B2R2_BLT_FLAG_BG_BLEND) && + !(request->user_req.flags & + B2R2_BLT_FLAG_BG_NO_CACHE_FLUSH) && + (request->user_req.bg_img.buf.type != + B2R2_BLT_PTR_PHYSICAL) && + !b2r2_is_mb_fmt(request->user_req.bg_img.fmt)) + /* MB formats are never touched by SW */ + sync_buf(cont, &request->user_req.bg_img, + &request->bg_resolved, false, + &request->user_req.bg_rect); + + /* Source mask buffer */ + if (!(request->user_req.flags & + B2R2_BLT_FLAG_SRC_MASK_NO_CACHE_FLUSH) && + (request->user_req.src_mask.buf.type != + B2R2_BLT_PTR_PHYSICAL) && + !b2r2_is_mb_fmt(request->user_req.src_mask.fmt)) + /* MB formats are never touched by SW */ + sync_buf(cont, &request->user_req.src_mask, + &request->src_mask_resolved, false, NULL); + + /* Destination buffer */ + if (!(request->user_req.flags & + B2R2_BLT_FLAG_DST_NO_CACHE_FLUSH) && + (request->user_req.dst_img.buf.type != + B2R2_BLT_PTR_PHYSICAL) && + !b2r2_is_mb_fmt(request->user_req.dst_img.fmt)) + /* MB formats are never touched by SW */ + sync_buf(cont, &request->user_req.dst_img, + &request->dst_resolved, true, + &request->user_req.dst_rect); + +#ifdef CONFIG_DEBUG_FS + /* Remember latest request for debugfs */ + cont->debugfs_latest_request = *request; +#endif + + /* Submit the job */ + b2r2_log_info(cont->dev, "%s: Submitting job\n", __func__); + + inc_stat(cont, &cont->stat_n_in_blt_add); + + if (request->profile) + request->nsec_active_in_cpu = + (s32)((u32)task_sched_runtime(current) - + thread_runtime_at_start); + + mutex_lock(&instance->lock); + + /* Add the job to b2r2_core */ + request_id = b2r2_core_job_add(cont, &request->job); + request->request_id = request_id; + + dec_stat(cont, &cont->stat_n_in_blt_add); + + if (request_id < 0) { + b2r2_log_warn(cont->dev, "%s: Failed to add job, ret = %d\n", + __func__, request_id); + ret = request_id; + mutex_unlock(&instance->lock); + goto job_add_failed; + } + + inc_stat(cont, &cont->stat_n_jobs_added); + + instance->no_of_active_requests++; + mutex_unlock(&instance->lock); + + /* Wait for the job to be done if synchronous */ + if ((request->user_req.flags & B2R2_BLT_FLAG_ASYNCH) == 0) { + b2r2_log_info(cont->dev, "%s: Synchronous, waiting\n", + __func__); + + inc_stat(cont, &cont->stat_n_in_blt_wait); + + ret = b2r2_core_job_wait(&request->job); + + dec_stat(cont, &cont->stat_n_in_blt_wait); + + if (ret < 0 && ret != -ENOENT) + b2r2_log_warn(cont->dev, "%s: Failed to wait job," + " ret = %d\n", __func__, ret); + else + b2r2_log_info(cont->dev, "%s: Synchronous wait done\n", + __func__); + ret = 0; + } + + /* + * Release matching the addref in b2r2_core_job_add, + * the request must not be accessed after this call + */ + b2r2_core_job_release(&request->job, __func__); + dec_stat(cont, &cont->stat_n_in_blt); + + return ret >= 0 ? request_id : ret; + +job_add_failed: +exit_dry_run: +no_optimized_path: +generate_nodes_failed: + unresolve_buf(cont, &request->user_req.dst_img.buf, + &request->dst_resolved); +resolve_dst_buf_failed: + unresolve_buf(cont, &request->user_req.src_mask.buf, + &request->src_mask_resolved); +resolve_src_mask_buf_failed: + if (request->user_req.flags & B2R2_BLT_FLAG_BG_BLEND) + unresolve_buf(cont, &request->user_req.bg_img.buf, + &request->bg_resolved); +resolve_bg_buf_failed: + unresolve_buf(cont, &request->user_req.src_img.buf, + &request->src_resolved); +resolve_src_buf_failed: +synch_interrupted: + job_release(&request->job); + dec_stat(cont, &cont->stat_n_jobs_released); + if ((request->user_req.flags & B2R2_BLT_FLAG_DRY_RUN) == 0 || ret) + b2r2_log_warn(cont->dev, "%s returns with error %d\n", + __func__, ret); + + dec_stat(cont, &cont->stat_n_in_blt); + + return ret; +} + +/** + * Called when job is done or cancelled + * + * @job: The job + */ +static void job_callback(struct b2r2_core_job *job) +{ + struct b2r2_blt_request *request = + container_of(job, struct b2r2_blt_request, job); + struct b2r2_control *cont = request->instance->control; + + if (cont->dev) + b2r2_log_info(cont->dev, "%s\n", __func__); + + /* Local addref / release within this func */ + b2r2_core_job_addref(job, __func__); + + /* Unresolve the buffers */ + unresolve_buf(cont, &request->user_req.src_img.buf, + &request->src_resolved); + unresolve_buf(cont, &request->user_req.src_mask.buf, + &request->src_mask_resolved); + unresolve_buf(cont, &request->user_req.dst_img.buf, + &request->dst_resolved); + if (request->user_req.flags & B2R2_BLT_FLAG_BG_BLEND) + unresolve_buf(cont, &request->user_req.bg_img.buf, + &request->bg_resolved); + + /* Move to report list if the job shall be reported */ + /* FIXME: Use a smaller struct? */ + mutex_lock(&request->instance->lock); + if (request->user_req.flags & B2R2_BLT_FLAG_REPORT_WHEN_DONE) { + /* Move job to report list */ + list_add_tail(&request->list, + &request->instance->report_list); + inc_stat(cont, &cont->stat_n_jobs_in_report_list); + + /* Wake up poll */ + wake_up_interruptible( + &request->instance->report_list_waitq); + + /* Add a reference because we put the job in the report list */ + b2r2_core_job_addref(job, __func__); + } + + /* + * Decrease number of active requests and wake up + * synching threads if active requests reaches zero + */ + BUG_ON(request->instance->no_of_active_requests == 0); + request->instance->no_of_active_requests--; + if (request->instance->synching && + request->instance->no_of_active_requests == 0) { + request->instance->synching = false; + /* Wake up all syncing */ + + wake_up_interruptible_all( + &request->instance->synch_done_waitq); + } + mutex_unlock(&request->instance->lock); + +#ifdef CONFIG_DEBUG_FS + /* Dump job if cancelled */ + if (job->job_state == B2R2_CORE_JOB_CANCELED) { + char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL); + + b2r2_log_info(cont->dev, "%s: Job cancelled:\n", __func__); + if (Buf != NULL) { + sprintf_req(request, Buf, sizeof(char) * 4096); + b2r2_log_info(cont->dev, "%s", Buf); + kfree(Buf); + } else { + b2r2_log_info(cont->dev, "Unable to print the request." + " Message buffer allocation failed.\n"); + } + } +#endif + + if (request->profile) { + request->total_time_nsec = + (s32)(b2r2_get_curr_nsec() - request->start_time_nsec); + b2r2_call_profiler_blt_done(request); + } + + /* Local addref / release within this func */ + b2r2_core_job_release(job, __func__); +} + +/** + * Called when job should be released (free memory etc.) + * + * @job: The job + */ +static void job_release(struct b2r2_core_job *job) +{ + struct b2r2_blt_request *request = + container_of(job, struct b2r2_blt_request, job); + struct b2r2_control *cont = request->instance->control; + + inc_stat(cont, &cont->stat_n_jobs_released); + + b2r2_log_info(cont->dev, "%s, first_node=%p, ref_count=%d\n", + __func__, request->first_node, request->job.ref_count); + + b2r2_node_split_cancel(cont, &request->node_split_job); + + if (request->first_node) { + b2r2_debug_job_done(cont, request->first_node); +#ifdef B2R2_USE_NODE_GEN + b2r2_blt_free_nodes(cont, request->first_node); +#else + b2r2_node_free(cont, request->first_node); +#endif + } + + /* Release memory for the request */ + if (request->clut != NULL) { + dma_free_coherent(cont->dev, CLUT_SIZE, request->clut, + request->clut_phys_addr); + request->clut = NULL; + request->clut_phys_addr = 0; + } + kfree(request); +} + +/** + * Tells the job to try to allocate the resources needed to execute the job. + * Called just before execution of a job. + * + * @job: The job + * @atomic: true if called from atomic (i.e. interrupt) context. If function + * can't allocate in atomic context it should return error, it + * will then be called later from non-atomic context. + */ +static int job_acquire_resources(struct b2r2_core_job *job, bool atomic) +{ + struct b2r2_blt_request *request = + container_of(job, struct b2r2_blt_request, job); + struct b2r2_control *cont = request->instance->control; + int ret; + int i; + + b2r2_log_info(cont->dev, "%s\n", __func__); + + if (request->buf_count == 0) + return 0; + + if (request->buf_count > MAX_TMP_BUFS_NEEDED) { + b2r2_log_err(cont->dev, + "%s: request->buf_count > MAX_TMP_BUFS_NEEDED\n", + __func__); + return -ENOMSG; + } + + /* + * 1 to 1 mapping between request temp buffers and temp buffers + * (request temp buf 0 is always temp buf 0, request temp buf 1 is + * always temp buf 1 and so on) to avoid starvation of jobs that + * require multiple temp buffers. Not optimal in terms of memory + * usage but we avoid get into a situation where lower prio jobs can + * delay higher prio jobs that require more temp buffers. + */ + if (cont->tmp_bufs[0].in_use) + return -EAGAIN; + + for (i = 0; i < request->buf_count; i++) { + if (cont->tmp_bufs[i].buf.size < request->bufs[i].size) { + b2r2_log_err(cont->dev, "%s: " + "cont->tmp_bufs[i].buf.size < " + "request->bufs[i].size\n", __func__); + ret = -ENOMSG; + goto error; + } + + cont->tmp_bufs[i].in_use = true; + request->bufs[i].phys_addr = cont->tmp_bufs[i].buf.phys_addr; + request->bufs[i].virt_addr = cont->tmp_bufs[i].buf.virt_addr; + + b2r2_log_info(cont->dev, "%s: phys=%p, virt=%p\n", + __func__, (void *)request->bufs[i].phys_addr, + request->bufs[i].virt_addr); + + ret = b2r2_node_split_assign_buffers(cont, + &request->node_split_job, + request->first_node, request->bufs, + request->buf_count); + if (ret < 0) + goto error; + } + + return 0; + +error: + for (i = 0; i < request->buf_count; i++) + cont->tmp_bufs[i].in_use = false; + + return ret; +} + +/** + * Tells the job to free the resources needed to execute the job. + * Called after execution of a job. + * + * @job: The job + * @atomic: true if called from atomic (i.e. interrupt) context. If function + * can't allocate in atomic context it should return error, it + * will then be called later from non-atomic context. + */ +static void job_release_resources(struct b2r2_core_job *job, bool atomic) +{ + struct b2r2_blt_request *request = + container_of(job, struct b2r2_blt_request, job); + struct b2r2_control *cont = request->instance->control; + int i; + + b2r2_log_info(cont->dev, "%s\n", __func__); + + /* Free any temporary buffers */ + for (i = 0; i < request->buf_count; i++) { + + b2r2_log_info(cont->dev, "%s: freeing %d bytes\n", + __func__, request->bufs[i].size); + cont->tmp_bufs[i].in_use = false; + memset(&request->bufs[i], 0, sizeof(request->bufs[i])); + } + request->buf_count = 0; + + /* + * Early release of nodes + * FIXME: If nodes are to be reused we don't want to release here + */ + if (!atomic && request->first_node) { + b2r2_debug_job_done(cont, request->first_node); + +#ifdef B2R2_USE_NODE_GEN + b2r2_blt_free_nodes(cont, request->first_node); +#else + b2r2_node_free(cont, request->first_node); +#endif + request->first_node = NULL; + } +} + +#endif /* !CONFIG_B2R2_GENERIC_ONLY */ + +#ifdef CONFIG_B2R2_GENERIC +/** + * Called when job for one tile is done or cancelled + * in the generic path. + * + * @job: The job + */ +static void tile_job_callback_gen(struct b2r2_core_job *job) +{ +#ifdef CONFIG_B2R2_DEBUG + struct b2r2_blt_instance *instance = + (struct b2r2_blt_instance *) job->tag; + struct b2r2_control *cont = instance->control; +#endif + + b2r2_log_info(cont->dev, "%s\n", __func__); + + /* Local addref / release within this func */ + b2r2_core_job_addref(job, __func__); + +#ifdef CONFIG_DEBUG_FS + /* Notify if a tile job is cancelled */ + if (job->job_state == B2R2_CORE_JOB_CANCELED) + b2r2_log_info(cont->dev, "%s: Tile job cancelled:\n", + __func__); +#endif + + /* Local addref / release within this func */ + b2r2_core_job_release(job, __func__); +} + +/** + * Called when job is done or cancelled. + * Used for the last tile in the generic path + * to notify waiting clients. + * + * @job: The job + */ +static void job_callback_gen(struct b2r2_core_job *job) +{ + struct b2r2_blt_request *request = + container_of(job, struct b2r2_blt_request, job); + struct b2r2_control *cont = request->instance->control; + + b2r2_log_info(cont->dev, "%s\n", __func__); + + /* Local addref / release within this func */ + b2r2_core_job_addref(job, __func__); + + /* Unresolve the buffers */ + unresolve_buf(cont, &request->user_req.src_img.buf, + &request->src_resolved); + unresolve_buf(cont, &request->user_req.src_mask.buf, + &request->src_mask_resolved); + unresolve_buf(cont, &request->user_req.dst_img.buf, + &request->dst_resolved); + + /* Move to report list if the job shall be reported */ + /* FIXME: Use a smaller struct? */ + mutex_lock(&request->instance->lock); + + if (request->user_req.flags & B2R2_BLT_FLAG_REPORT_WHEN_DONE) { + /* Move job to report list */ + list_add_tail(&request->list, + &request->instance->report_list); + inc_stat(cont, &cont->stat_n_jobs_in_report_list); + + /* Wake up poll */ + wake_up_interruptible( + &request->instance->report_list_waitq); + + /* + * Add a reference because we put the + * job in the report list + */ + b2r2_core_job_addref(job, __func__); + } + + /* + * Decrease number of active requests and wake up + * synching threads if active requests reaches zero + */ + BUG_ON(request->instance->no_of_active_requests == 0); + request->instance->no_of_active_requests--; + if (request->instance->synching && + request->instance->no_of_active_requests == 0) { + request->instance->synching = false; + /* Wake up all syncing */ + + wake_up_interruptible_all( + &request->instance->synch_done_waitq); + } + mutex_unlock(&request->instance->lock); + +#ifdef CONFIG_DEBUG_FS + /* Dump job if cancelled */ + if (job->job_state == B2R2_CORE_JOB_CANCELED) { + char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL); + + b2r2_log_info(cont->dev, "%s: Job cancelled:\n", __func__); + if (Buf != NULL) { + sprintf_req(request, Buf, sizeof(char) * 4096); + b2r2_log_info(cont->dev, "%s", Buf); + kfree(Buf); + } else { + b2r2_log_info(cont->dev, "Unable to print the request." + " Message buffer allocation failed.\n"); + } + } +#endif + + /* Local addref / release within this func */ + b2r2_core_job_release(job, __func__); +} + +/** + * Called when tile job should be released (free memory etc.) + * Should be used only for tile jobs. Tile jobs should only be used + * by b2r2_core, thus making ref_count trigger their release. + * + * @job: The job + */ + +static void tile_job_release_gen(struct b2r2_core_job *job) +{ + struct b2r2_blt_instance *instance = + (struct b2r2_blt_instance *) job->tag; + struct b2r2_control *cont = instance->control; + + inc_stat(cont, &cont->stat_n_jobs_released); + + b2r2_log_info(cont->dev, "%s, first_node_address=0x%.8x, ref_count=" + "%d\n", __func__, job->first_node_address, + job->ref_count); + + /* Release memory for the job */ + kfree(job); +} + +/** + * Called when job should be released (free memory etc.) + * + * @job: The job + */ + +static void job_release_gen(struct b2r2_core_job *job) +{ + struct b2r2_blt_request *request = + container_of(job, struct b2r2_blt_request, job); + struct b2r2_control *cont = request->instance->control; + + inc_stat(cont, &cont->stat_n_jobs_released); + + b2r2_log_info(cont->dev, "%s, first_node=%p, ref_count=%d\n", + __func__, request->first_node, request->job.ref_count); + + if (request->first_node) { + b2r2_debug_job_done(cont, request->first_node); + + /* Free nodes */ +#ifdef B2R2_USE_NODE_GEN + b2r2_blt_free_nodes(cont, request->first_node); +#else + b2r2_node_free(cont, request->first_node); +#endif + } + + /* Release memory for the request */ + if (request->clut != NULL) { + dma_free_coherent(cont->dev, CLUT_SIZE, request->clut, + request->clut_phys_addr); + request->clut = NULL; + request->clut_phys_addr = 0; + } + kfree(request); +} + +static int job_acquire_resources_gen(struct b2r2_core_job *job, bool atomic) +{ + /* Nothing so far. Temporary buffers are pre-allocated */ + return 0; +} +static void job_release_resources_gen(struct b2r2_core_job *job, bool atomic) +{ + /* Nothing so far. Temporary buffers are pre-allocated */ +} + +/** + * b2r2_generic_blt - Generic implementation of the B2R2 blit request + * + * @instance: The B2R2 BLT instance + * @request; The request to perform + */ +static int b2r2_generic_blt(struct b2r2_blt_instance *instance, + struct b2r2_blt_request *request) +{ + int ret = 0; + struct b2r2_blt_rect actual_dst_rect; + int request_id = 0; + struct b2r2_node *last_node = request->first_node; + int node_count; + s32 tmp_buf_width = 0; + s32 tmp_buf_height = 0; + u32 tmp_buf_count = 0; + s32 x; + s32 y; + const struct b2r2_blt_rect *dst_rect = &(request->user_req.dst_rect); + const s32 dst_img_width = request->user_req.dst_img.width; + const s32 dst_img_height = request->user_req.dst_img.height; + const enum b2r2_blt_flag flags = request->user_req.flags; + /* Descriptors for the temporary buffers */ + struct b2r2_work_buf work_bufs[4]; + struct b2r2_blt_rect dst_rect_tile; + int i; + struct b2r2_control *cont = instance->control; + + u32 thread_runtime_at_start = 0; + s32 nsec_active_in_b2r2 = 0; + + /* + * Early exit if zero blt. + * dst_rect outside of dst_img or + * dst_clip_rect outside of dst_img. + */ + if (dst_rect->x + dst_rect->width <= 0 || + dst_rect->y + dst_rect->height <= 0 || + dst_img_width <= dst_rect->x || + dst_img_height <= dst_rect->y || + ((flags & B2R2_BLT_FLAG_DESTINATION_CLIP) != 0 && + (dst_img_width <= request->user_req.dst_clip_rect.x || + dst_img_height <= request->user_req.dst_clip_rect.y || + request->user_req.dst_clip_rect.x + + request->user_req.dst_clip_rect.width <= 0 || + request->user_req.dst_clip_rect.y + + request->user_req.dst_clip_rect.height <= 0))) { + goto zero_blt; + } + + if (request->profile) { + request->start_time_nsec = b2r2_get_curr_nsec(); + thread_runtime_at_start = (u32)task_sched_runtime(current); + } + + memset(work_bufs, 0, sizeof(work_bufs)); + + b2r2_log_info(cont->dev, "%s\n", __func__); + + inc_stat(cont, &cont->stat_n_in_blt); + + /* Debug prints of incoming request */ + b2r2_log_info(cont->dev, + "src.fmt=%#010x flags=0x%.8x src.buf={%d,%d,0x%.8x}\n" + "src.w,h={%d,%d} src.rect={%d,%d,%d,%d}\n", + request->user_req.src_img.fmt, + request->user_req.flags, + request->user_req.src_img.buf.type, + request->user_req.src_img.buf.fd, + request->user_req.src_img.buf.offset, + request->user_req.src_img.width, + request->user_req.src_img.height, + request->user_req.src_rect.x, + request->user_req.src_rect.y, + request->user_req.src_rect.width, + request->user_req.src_rect.height); + b2r2_log_info(cont->dev, + "dst.fmt=%#010x dst.buf={%d,%d,0x%.8x}\n" + "dst.w,h={%d,%d} dst.rect={%d,%d,%d,%d}\n" + "dst_clip_rect={%d,%d,%d,%d}\n", + request->user_req.dst_img.fmt, + request->user_req.dst_img.buf.type, + request->user_req.dst_img.buf.fd, + request->user_req.dst_img.buf.offset, + request->user_req.dst_img.width, + request->user_req.dst_img.height, + request->user_req.dst_rect.x, + request->user_req.dst_rect.y, + request->user_req.dst_rect.width, + request->user_req.dst_rect.height, + request->user_req.dst_clip_rect.x, + request->user_req.dst_clip_rect.y, + request->user_req.dst_clip_rect.width, + request->user_req.dst_clip_rect.height); + + inc_stat(cont, &cont->stat_n_in_blt_synch); + + /* Wait here if synch is ongoing */ + ret = wait_event_interruptible(instance->synch_done_waitq, + !is_synching(instance)); + if (ret) { + b2r2_log_warn(cont->dev, "%s: Sync wait interrupted, %d\n", + __func__, ret); + ret = -EAGAIN; + dec_stat(cont, &cont->stat_n_in_blt_synch); + goto synch_interrupted; + } + + dec_stat(cont, &cont->stat_n_in_blt_synch); + + /* Resolve the buffers */ + + /* Source buffer */ + ret = resolve_buf(cont, &request->user_req.src_img, + &request->user_req.src_rect, false, &request->src_resolved); + if (ret < 0) { + b2r2_log_warn(cont->dev, "%s: Resolve src buf failed, %d\n", + __func__, ret); + ret = -EAGAIN; + goto resolve_src_buf_failed; + } + + /* Source mask buffer */ + ret = resolve_buf(cont, &request->user_req.src_mask, + &request->user_req.src_rect, false, + &request->src_mask_resolved); + if (ret < 0) { + b2r2_log_warn(cont->dev, + "%s: Resolve src mask buf failed, %d\n", + __func__, ret); + ret = -EAGAIN; + goto resolve_src_mask_buf_failed; + } + + /* Destination buffer */ + get_actual_dst_rect(&request->user_req, &actual_dst_rect); + ret = resolve_buf(cont, &request->user_req.dst_img, &actual_dst_rect, + true, &request->dst_resolved); + if (ret < 0) { + b2r2_log_warn(cont->dev, "%s: Resolve dst buf failed, %d\n", + __func__, ret); + ret = -EAGAIN; + goto resolve_dst_buf_failed; + } + + /* Debug prints of resolved buffers */ + b2r2_log_info(cont->dev, "src.rbuf={%X,%p,%d} {%p,%X,%X,%d}\n", + request->src_resolved.physical_address, + request->src_resolved.virtual_address, + request->src_resolved.is_pmem, + request->src_resolved.filep, + request->src_resolved.file_physical_start, + request->src_resolved.file_virtual_start, + request->src_resolved.file_len); + + b2r2_log_info(cont->dev, "dst.rbuf={%X,%p,%d} {%p,%X,%X,%d}\n", + request->dst_resolved.physical_address, + request->dst_resolved.virtual_address, + request->dst_resolved.is_pmem, + request->dst_resolved.filep, + request->dst_resolved.file_physical_start, + request->dst_resolved.file_virtual_start, + request->dst_resolved.file_len); + + /* Calculate the number of nodes (and resources) needed for this job */ + ret = b2r2_generic_analyze(request, &tmp_buf_width, + &tmp_buf_height, &tmp_buf_count, &node_count); + if (ret < 0) { + b2r2_log_warn(cont->dev, + "%s: Failed to analyze request, ret = %d\n", + __func__, ret); +#ifdef CONFIG_DEBUG_FS + { + /* Failed, dump job to dmesg */ + char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL); + + b2r2_log_info(cont->dev, + "%s: Analyze failed for:\n", __func__); + if (Buf != NULL) { + sprintf_req(request, Buf, sizeof(char) * 4096); + b2r2_log_info(cont->dev, "%s", Buf); + kfree(Buf); + } else { + b2r2_log_info(cont->dev, + "Unable to print the request. " + "Message buffer allocation failed.\n"); + } + } +#endif + goto generate_nodes_failed; + } + + /* Allocate the nodes needed */ +#ifdef B2R2_USE_NODE_GEN + request->first_node = b2r2_blt_alloc_nodes(cont, node_count); + if (request->first_node == NULL) { + b2r2_log_warn(cont->dev, + "%s: Failed to allocate nodes, ret = %d\n", + __func__, ret); + goto generate_nodes_failed; + } +#else + ret = b2r2_node_alloc(cont, node_count, &(request->first_node)); + if (ret < 0 || request->first_node == NULL) { + b2r2_log_warn(cont->dev, + "%s: Failed to allocate nodes, ret = %d\n", + __func__, ret); + goto generate_nodes_failed; + } +#endif + + /* Allocate the temporary buffers */ + for (i = 0; i < tmp_buf_count; i++) { + void *virt; + work_bufs[i].size = tmp_buf_width * tmp_buf_height * 4; + + virt = dma_alloc_coherent(cont->dev, + work_bufs[i].size, + &(work_bufs[i].phys_addr), + GFP_DMA | GFP_KERNEL); + if (virt == NULL) { + ret = -ENOMEM; + goto alloc_work_bufs_failed; + } + + work_bufs[i].virt_addr = virt; + memset(work_bufs[i].virt_addr, 0xff, work_bufs[i].size); + } + ret = b2r2_generic_configure(request, + request->first_node, &work_bufs[0], tmp_buf_count); + + if (ret < 0) { + b2r2_log_warn(cont->dev, + "%s: Failed to perform generic configure, ret = %d\n", + __func__, ret); + goto generic_conf_failed; + } + + /* Exit here if dry run */ + if (flags & B2R2_BLT_FLAG_DRY_RUN) + goto exit_dry_run; + + /* + * Configure the request and make sure + * that its job is run only for the LAST tile. + * This is when the request is complete + * and waiting clients should be notified. + */ + last_node = request->first_node; + while (last_node && last_node->next) + last_node = last_node->next; + + request->job.tag = (int) instance; + request->job.prio = request->user_req.prio; + request->job.first_node_address = + request->first_node->physical_address; + request->job.last_node_address = + last_node->physical_address; + request->job.callback = job_callback_gen; + request->job.release = job_release_gen; + /* Work buffers and nodes are pre-allocated */ + request->job.acquire_resources = job_acquire_resources_gen; + request->job.release_resources = job_release_resources_gen; + + /* Flush the L1/L2 cache for the buffers */ + + /* Source buffer */ + if (!(flags & B2R2_BLT_FLAG_SRC_NO_CACHE_FLUSH) && + (request->user_req.src_img.buf.type != + B2R2_BLT_PTR_PHYSICAL) && + !b2r2_is_mb_fmt(request->user_req.src_img.fmt)) + /* MB formats are never touched by SW */ + sync_buf(cont, &request->user_req.src_img, + &request->src_resolved, + false, /*is_dst*/ + &request->user_req.src_rect); + + /* Source mask buffer */ + if (!(flags & B2R2_BLT_FLAG_SRC_MASK_NO_CACHE_FLUSH) && + (request->user_req.src_mask.buf.type != + B2R2_BLT_PTR_PHYSICAL) && + !b2r2_is_mb_fmt(request->user_req.src_mask.fmt)) + /* MB formats are never touched by SW */ + sync_buf(cont, &request->user_req.src_mask, + &request->src_mask_resolved, + false, /*is_dst*/ + NULL); + + /* Destination buffer */ + if (!(flags & B2R2_BLT_FLAG_DST_NO_CACHE_FLUSH) && + (request->user_req.dst_img.buf.type != + B2R2_BLT_PTR_PHYSICAL) && + !b2r2_is_mb_fmt(request->user_req.dst_img.fmt)) + /* MB formats are never touched by SW */ + sync_buf(cont, &request->user_req.dst_img, + &request->dst_resolved, + true, /*is_dst*/ + &request->user_req.dst_rect); + +#ifdef CONFIG_DEBUG_FS + /* Remember latest request */ + cont->debugfs_latest_request = *request; +#endif + + /* + * Same nodes are reused for all the jobs needed to complete the blit. + * Nodes are NOT released together with associated job, + * as is the case with optimized b2r2_blt() path. + */ + mutex_lock(&instance->lock); + instance->no_of_active_requests++; + mutex_unlock(&instance->lock); + /* + * Process all but the last row in the destination rectangle. + * Consider only the tiles that will actually end up inside + * the destination image. + * dst_rect->height - tmp_buf_height being <=0 is allright. + * The loop will not be entered since y will always be equal to or + * greater than zero. + * Early exit check at the beginning handles the cases when nothing + * at all should be processed. + */ + y = 0; + if (dst_rect->y < 0) + y = -dst_rect->y; + + for (; y < dst_rect->height - tmp_buf_height && + y + dst_rect->y < dst_img_height - tmp_buf_height; + y += tmp_buf_height) { + /* Tile in the destination rectangle being processed */ + struct b2r2_blt_rect dst_rect_tile; + dst_rect_tile.y = y; + dst_rect_tile.width = tmp_buf_width; + dst_rect_tile.height = tmp_buf_height; + + x = 0; + if (dst_rect->x < 0) + x = -dst_rect->x; + + for (; x < dst_rect->width && x + dst_rect->x < dst_img_width; + x += tmp_buf_width) { + /* + * Tile jobs are freed by the supplied release function + * when ref_count on a tile_job reaches zero. + */ + struct b2r2_core_job *tile_job = + kmalloc(sizeof(*tile_job), GFP_KERNEL); + if (tile_job == NULL) { + /* + * Skip this tile. Do not abort, + * just hope for better luck + * with rest of the tiles. + * Memory might become available. + */ + b2r2_log_info(cont->dev, "%s: Failed to alloc " + "job. Skipping tile at (x, y)=" + "(%d, %d)\n", __func__, x, y); + continue; + } + tile_job->tag = request->job.tag; + tile_job->prio = request->job.prio; + tile_job->first_node_address = + request->job.first_node_address; + tile_job->last_node_address = + request->job.last_node_address; + tile_job->callback = tile_job_callback_gen; + tile_job->release = tile_job_release_gen; + /* Work buffers and nodes are pre-allocated */ + tile_job->acquire_resources = + job_acquire_resources_gen; + tile_job->release_resources = + job_release_resources_gen; + + dst_rect_tile.x = x; + if (x + dst_rect->x + tmp_buf_width > dst_img_width) { + /* + * Only a part of the tile can be written. + * Limit imposed by buffer size. + */ + dst_rect_tile.width = + dst_img_width - (x + dst_rect->x); + } else if (x + tmp_buf_width > dst_rect->width) { + /* + * Only a part of the tile can be written. + * In this case limit imposed by dst_rect size. + */ + dst_rect_tile.width = dst_rect->width - x; + } else { + /* Whole tile can be written. */ + dst_rect_tile.width = tmp_buf_width; + } + /* + * Where applicable, calculate area in src buffer + * that is needed to generate the specified part + * of destination rectangle. + */ + b2r2_generic_set_areas(request, + request->first_node, &dst_rect_tile); + /* Submit the job */ + b2r2_log_info(cont->dev, + "%s: Submitting job\n", __func__); + + inc_stat(cont, &cont->stat_n_in_blt_add); + + mutex_lock(&instance->lock); + + request_id = b2r2_core_job_add(cont, tile_job); + + dec_stat(cont, &cont->stat_n_in_blt_add); + + if (request_id < 0) { + b2r2_log_warn(cont->dev, "%s: " + "Failed to add tile job, ret = %d\n", + __func__, request_id); + ret = request_id; + mutex_unlock(&instance->lock); + goto job_add_failed; + } + + inc_stat(cont, &cont->stat_n_jobs_added); + + mutex_unlock(&instance->lock); + + /* Wait for the job to be done */ + b2r2_log_info(cont->dev, "%s: Synchronous, waiting\n", + __func__); + + inc_stat(cont, &cont->stat_n_in_blt_wait); + + ret = b2r2_core_job_wait(tile_job); + + dec_stat(cont, &cont->stat_n_in_blt_wait); + + if (ret < 0 && ret != -ENOENT) + b2r2_log_warn(cont->dev, + "%s: Failed to wait job, ret = %d\n", + __func__, ret); + else { + b2r2_log_info(cont->dev, + "%s: Synchronous wait done\n", + __func__); + + nsec_active_in_b2r2 += + tile_job->nsec_active_in_hw; + } + /* Release matching the addref in b2r2_core_job_add */ + b2r2_core_job_release(tile_job, __func__); + } + } + + x = 0; + if (dst_rect->x < 0) + x = -dst_rect->x; + + for (; x < dst_rect->width && + x + dst_rect->x < dst_img_width; x += tmp_buf_width) { + struct b2r2_core_job *tile_job = NULL; + if (x + tmp_buf_width < dst_rect->width && + x + dst_rect->x + tmp_buf_width < + dst_img_width) { + /* + * Tile jobs are freed by the supplied release function + * when ref_count on a tile_job reaches zero. + * Do NOT allocate a tile_job for the last tile. + * Send the job from the request. This way clients + * will be notified when the whole blit is complete + * and not just part of it. + */ + tile_job = kmalloc(sizeof(*tile_job), GFP_KERNEL); + if (tile_job == NULL) { + b2r2_log_info(cont->dev, "%s: Failed to alloc " + "job. Skipping tile at (x, y)=" + "(%d, %d)\n", __func__, x, y); + continue; + } + tile_job->tag = request->job.tag; + tile_job->prio = request->job.prio; + tile_job->first_node_address = + request->job.first_node_address; + tile_job->last_node_address = + request->job.last_node_address; + tile_job->callback = tile_job_callback_gen; + tile_job->release = tile_job_release_gen; + tile_job->acquire_resources = + job_acquire_resources_gen; + tile_job->release_resources = + job_release_resources_gen; + } + + dst_rect_tile.x = x; + if (x + dst_rect->x + tmp_buf_width > dst_img_width) { + /* + * Only a part of the tile can be written. + * Limit imposed by buffer size. + */ + dst_rect_tile.width = dst_img_width - (x + dst_rect->x); + } else if (x + tmp_buf_width > dst_rect->width) { + /* + * Only a part of the tile can be written. + * In this case limit imposed by dst_rect size. + */ + dst_rect_tile.width = dst_rect->width - x; + } else { + /* Whole tile can be written. */ + dst_rect_tile.width = tmp_buf_width; + } + /* + * y is now the last row. Either because the whole dst_rect + * has been processed, or because the last row that will be + * written to dst_img has been reached. Limits imposed in + * the same way as for width. + */ + dst_rect_tile.y = y; + if (y + dst_rect->y + tmp_buf_height > dst_img_height) + dst_rect_tile.height = + dst_img_height - (y + dst_rect->y); + else if (y + tmp_buf_height > dst_rect->height) + dst_rect_tile.height = dst_rect->height - y; + else + dst_rect_tile.height = tmp_buf_height; + + b2r2_generic_set_areas(request, + request->first_node, &dst_rect_tile); + + b2r2_log_info(cont->dev, "%s: Submitting job\n", __func__); + inc_stat(cont, &cont->stat_n_in_blt_add); + + mutex_lock(&instance->lock); + if (x + tmp_buf_width < dst_rect->width && + x + dst_rect->x + tmp_buf_width < + dst_img_width) { + request_id = b2r2_core_job_add(cont, tile_job); + } else { + /* + * Last tile. Send the job-struct from the request. + * Clients will be notified once it completes. + */ + request_id = b2r2_core_job_add(cont, &request->job); + } + + dec_stat(cont, &cont->stat_n_in_blt_add); + + if (request_id < 0) { + b2r2_log_warn(cont->dev, "%s: Failed to add tile job, " + "ret = %d\n", __func__, request_id); + ret = request_id; + mutex_unlock(&instance->lock); + if (tile_job != NULL) + kfree(tile_job); + goto job_add_failed; + } + + inc_stat(cont, &cont->stat_n_jobs_added); + mutex_unlock(&instance->lock); + + b2r2_log_info(cont->dev, "%s: Synchronous, waiting\n", + __func__); + + inc_stat(cont, &cont->stat_n_in_blt_wait); + if (x + tmp_buf_width < dst_rect->width && + x + dst_rect->x + tmp_buf_width < + dst_img_width) { + ret = b2r2_core_job_wait(tile_job); + } else { + /* + * This is the last tile. Wait for the job-struct from + * the request. + */ + ret = b2r2_core_job_wait(&request->job); + } + dec_stat(cont, &cont->stat_n_in_blt_wait); + + if (ret < 0 && ret != -ENOENT) + b2r2_log_warn(cont->dev, + "%s: Failed to wait job, ret = %d\n", + __func__, ret); + else { + b2r2_log_info(cont->dev, + "%s: Synchronous wait done\n", __func__); + + if (x + tmp_buf_width < dst_rect->width && + x + dst_rect->x + tmp_buf_width < + dst_img_width) + nsec_active_in_b2r2 += + tile_job->nsec_active_in_hw; + else + nsec_active_in_b2r2 += + request->job.nsec_active_in_hw; + } + + /* + * Release matching the addref in b2r2_core_job_add. + * Make sure that the correct job-struct is released + * when the last tile is processed. + */ + if (x + tmp_buf_width < dst_rect->width && + x + dst_rect->x + tmp_buf_width < + dst_img_width) { + b2r2_core_job_release(tile_job, __func__); + } else { + /* + * Update profiling information before + * the request is released together with + * its core_job. + */ + if (request->profile) { + request->nsec_active_in_cpu = + (s32)((u32)task_sched_runtime(current) - + thread_runtime_at_start); + request->total_time_nsec = + (s32)(b2r2_get_curr_nsec() - + request->start_time_nsec); + request->job.nsec_active_in_hw = + nsec_active_in_b2r2; + + b2r2_call_profiler_blt_done(request); + } + + b2r2_core_job_release(&request->job, __func__); + } + } + + dec_stat(cont, &cont->stat_n_in_blt); + + for (i = 0; i < tmp_buf_count; i++) { + dma_free_coherent(cont->dev, + work_bufs[i].size, + work_bufs[i].virt_addr, + work_bufs[i].phys_addr); + memset(&(work_bufs[i]), 0, sizeof(work_bufs[i])); + } + + return request_id; + +job_add_failed: +exit_dry_run: +generic_conf_failed: +alloc_work_bufs_failed: + for (i = 0; i < 4; i++) { + if (work_bufs[i].virt_addr != 0) { + dma_free_coherent(cont->dev, + work_bufs[i].size, + work_bufs[i].virt_addr, + work_bufs[i].phys_addr); + memset(&(work_bufs[i]), 0, sizeof(work_bufs[i])); + } + } + +generate_nodes_failed: + unresolve_buf(cont, &request->user_req.dst_img.buf, + &request->dst_resolved); +resolve_dst_buf_failed: + unresolve_buf(cont, &request->user_req.src_mask.buf, + &request->src_mask_resolved); +resolve_src_mask_buf_failed: + unresolve_buf(cont, &request->user_req.src_img.buf, + &request->src_resolved); +resolve_src_buf_failed: +synch_interrupted: +zero_blt: + job_release_gen(&request->job); + dec_stat(cont, &cont->stat_n_jobs_released); + dec_stat(cont, &cont->stat_n_in_blt); + + b2r2_log_info(cont->dev, "b2r2:%s ret=%d", __func__, ret); + return ret; +} +#endif /* CONFIG_B2R2_GENERIC */ + +/** + * b2r2_blt_synch - Implements wait for all or a specified job + * + * @instance: The B2R2 BLT instance + * @request_id: If 0, wait for all requests on this instance to finish. + * Else wait for request with given request id to finish. + */ +static int b2r2_blt_synch(struct b2r2_blt_instance *instance, + int request_id) +{ + int ret = 0; + struct b2r2_control *cont = instance->control; + + b2r2_log_info(cont->dev, "%s, request_id=%d\n", __func__, request_id); + + if (request_id == 0) { + /* Wait for all requests */ + inc_stat(cont, &cont->stat_n_in_synch_0); + + /* Enter state "synching" if we have any active request */ + mutex_lock(&instance->lock); + if (instance->no_of_active_requests) + instance->synching = true; + mutex_unlock(&instance->lock); + + /* Wait until no longer in state synching */ + ret = wait_event_interruptible(instance->synch_done_waitq, + !is_synching(instance)); + dec_stat(cont, &cont->stat_n_in_synch_0); + } else { + struct b2r2_core_job *job; + + inc_stat(cont, &cont->stat_n_in_synch_job); + + /* Wait for specific job */ + job = b2r2_core_job_find(cont, request_id); + if (job) { + /* Wait on find job */ + ret = b2r2_core_job_wait(job); + /* Release matching the addref in b2r2_core_job_find */ + b2r2_core_job_release(job, __func__); + } + + /* If job not found we assume that is has been run */ + dec_stat(cont, &cont->stat_n_in_synch_job); + } + + b2r2_log_info(cont->dev, + "%s, request_id=%d, returns %d\n", __func__, request_id, ret); + + return ret; +} + +/** + * Query B2R2 capabilities + * + * @instance: The B2R2 BLT instance + * @query_cap: The structure receiving the capabilities + */ +static int b2r2_blt_query_cap(struct b2r2_blt_instance *instance, + struct b2r2_blt_query_cap *query_cap) +{ + /* FIXME: Not implemented yet */ + return -ENOSYS; +} + +static void get_actual_dst_rect(struct b2r2_blt_req *req, + struct b2r2_blt_rect *actual_dst_rect) +{ + struct b2r2_blt_rect dst_img_bounds; + + b2r2_get_img_bounding_rect(&req->dst_img, &dst_img_bounds); + + b2r2_intersect_rects(&req->dst_rect, &dst_img_bounds, actual_dst_rect); + + if (req->flags & B2R2_BLT_FLAG_DESTINATION_CLIP) + b2r2_intersect_rects(actual_dst_rect, &req->dst_clip_rect, + actual_dst_rect); +} + +static void set_up_hwmem_region(struct b2r2_control *cont, + struct b2r2_blt_img *img, struct b2r2_blt_rect *rect, + struct hwmem_region *region) +{ + s32 img_size; + + memset(region, 0, sizeof(*region)); + + if (b2r2_is_zero_area_rect(rect)) + return; + + img_size = b2r2_get_img_size(cont, img); + + if (b2r2_is_single_plane_fmt(img->fmt) && + b2r2_is_independent_pixel_fmt(img->fmt)) { + int img_fmt_bpp = b2r2_get_fmt_bpp(cont, img->fmt); + u32 img_pitch = b2r2_get_img_pitch(cont, img); + + region->offset = (u32)(img->buf.offset + (rect->y * + img_pitch)); + region->count = (u32)rect->height; + region->start = (u32)((rect->x * img_fmt_bpp) / 8); + region->end = (u32)b2r2_div_round_up( + (rect->x + rect->width) * img_fmt_bpp, 8); + region->size = img_pitch; + } else { + /* + * TODO: Locking entire buffer as a quick safe solution. In the + * future we should lock less to avoid unecessary cache + * synching. Pixel interleaved YCbCr formats should be quite + * easy, just align start and stop points on 2. + */ + region->offset = (u32)img->buf.offset; + region->count = 1; + region->start = 0; + region->end = (u32)img_size; + region->size = (u32)img_size; + } +} + +static int resolve_hwmem(struct b2r2_control *cont, + struct b2r2_blt_img *img, + struct b2r2_blt_rect *rect_2b_used, + bool is_dst, + struct b2r2_resolved_buf *resolved_buf) +{ + int return_value = 0; + enum hwmem_mem_type mem_type; + enum hwmem_access access; + enum hwmem_access required_access; + struct hwmem_mem_chunk mem_chunk; + size_t mem_chunk_length = 1; + struct hwmem_region region; + + resolved_buf->hwmem_alloc = + hwmem_resolve_by_name(img->buf.hwmem_buf_name); + if (IS_ERR(resolved_buf->hwmem_alloc)) { + return_value = PTR_ERR(resolved_buf->hwmem_alloc); + b2r2_log_info(cont->dev, "%s: hwmem_resolve_by_name failed, " + "error code: %i\n", __func__, return_value); + goto resolve_failed; + } + + hwmem_get_info(resolved_buf->hwmem_alloc, &resolved_buf->file_len, + &mem_type, &access); + + required_access = (is_dst ? HWMEM_ACCESS_WRITE : HWMEM_ACCESS_READ) | + HWMEM_ACCESS_IMPORT; + if ((required_access & access) != required_access) { + b2r2_log_info(cont->dev, "%s: Insufficient access to hwmem " + "buffer.\n", __func__); + return_value = -EACCES; + goto access_check_failed; + } + + if (mem_type != HWMEM_MEM_CONTIGUOUS_SYS) { + b2r2_log_info(cont->dev, "%s: Hwmem buffer is scattered.\n", + __func__); + return_value = -EINVAL; + goto buf_scattered; + } + + if (resolved_buf->file_len < + img->buf.offset + (__u32)b2r2_get_img_size(cont, img)) { + b2r2_log_info(cont->dev, "%s: Hwmem buffer too small. (%d < " + "%d)\n", __func__, resolved_buf->file_len, + img->buf.offset + + (__u32)b2r2_get_img_size(cont, img)); + return_value = -EINVAL; + goto size_check_failed; + } + + return_value = hwmem_pin(resolved_buf->hwmem_alloc, &mem_chunk, + &mem_chunk_length); + if (return_value < 0) { + b2r2_log_info(cont->dev, "%s: hwmem_pin failed, " + "error code: %i\n", __func__, return_value); + goto pin_failed; + } + resolved_buf->file_physical_start = mem_chunk.paddr; + + set_up_hwmem_region(cont, img, rect_2b_used, ®ion); + return_value = hwmem_set_domain(resolved_buf->hwmem_alloc, + required_access, HWMEM_DOMAIN_SYNC, ®ion); + if (return_value < 0) { + b2r2_log_info(cont->dev, "%s: hwmem_set_domain failed, " + "error code: %i\n", __func__, return_value); + goto set_domain_failed; + } + + resolved_buf->physical_address = + resolved_buf->file_physical_start + img->buf.offset; + + goto out; + +set_domain_failed: + hwmem_unpin(resolved_buf->hwmem_alloc); +pin_failed: +size_check_failed: +buf_scattered: +access_check_failed: + hwmem_release(resolved_buf->hwmem_alloc); +resolve_failed: + +out: + return return_value; +} + +static void unresolve_hwmem(struct b2r2_resolved_buf *resolved_buf) +{ + hwmem_unpin(resolved_buf->hwmem_alloc); + hwmem_release(resolved_buf->hwmem_alloc); +} + +/** + * unresolve_buf() - Must be called after resolve_buf + * + * @buf: The buffer specification as supplied from user space + * @resolved: Gathered information about the buffer + * + * Returns 0 if OK else negative error code + */ +static void unresolve_buf(struct b2r2_control *cont, + struct b2r2_blt_buf *buf, + struct b2r2_resolved_buf *resolved) +{ +#ifdef CONFIG_ANDROID_PMEM + if (resolved->is_pmem && resolved->filep) + put_pmem_file(resolved->filep); +#endif + if (resolved->hwmem_alloc != NULL) + unresolve_hwmem(resolved); +} + +/** + * get_fb_info() - Fill buf with framebuffer info + * + * @file: The framebuffer file + * @buf: Gathered information about the buffer + * @img_offset: Image offset info frame buffer + * + * Returns 0 if OK else negative error code + */ +static int get_fb_info(struct file *file, + struct b2r2_resolved_buf *buf, + __u32 img_offset) +{ +#ifdef CONFIG_FB + if (file && buf && + MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) { + int i; + /* + * (OK to do it like this, no locking???) + */ + for (i = 0; i < num_registered_fb; i++) { + struct fb_info *info = registered_fb[i]; + + if (info && info->dev && + MINOR(info->dev->devt) == + MINOR(file->f_dentry->d_inode->i_rdev)) { + buf->file_physical_start = info->fix.smem_start; + buf->file_virtual_start = (u32)info->screen_base; + buf->file_len = info->fix.smem_len; + buf->physical_address = buf->file_physical_start + + img_offset; + buf->virtual_address = + (void *) (buf->file_virtual_start + + img_offset); + return 0; + } + } + } +#endif + return -EINVAL; +} + +/** + * resolve_buf() - Returns the physical & virtual addresses of a B2R2 blt buffer + * + * @img: The image specification as supplied from user space + * @rect_2b_used: The part of the image b2r2 will use. + * @usage: Specifies how the buffer will be used. + * @resolved: Gathered information about the buffer + * + * Returns 0 if OK else negative error code + */ +static int resolve_buf(struct b2r2_control *cont, + struct b2r2_blt_img *img, + struct b2r2_blt_rect *rect_2b_used, + bool is_dst, + struct b2r2_resolved_buf *resolved) +{ + int ret = 0; + + memset(resolved, 0, sizeof(*resolved)); + + switch (img->buf.type) { + case B2R2_BLT_PTR_NONE: + break; + + case B2R2_BLT_PTR_PHYSICAL: + resolved->physical_address = img->buf.offset; + resolved->file_len = img->buf.len; + break; + + /* FD + OFFSET type */ + case B2R2_BLT_PTR_FD_OFFSET: { + /* + * TODO: Do we need to check if the process is allowed to + * read/write (depending on if it's dst or src) to the file? + */ +#ifdef CONFIG_ANDROID_PMEM + if (!get_pmem_file( + img->buf.fd, + (unsigned long *) &resolved->file_physical_start, + (unsigned long *) &resolved->file_virtual_start, + (unsigned long *) &resolved->file_len, + &resolved->filep)) { + resolved->physical_address = + resolved->file_physical_start + + img->buf.offset; + resolved->virtual_address = (void *) + (resolved->file_virtual_start + + img->buf.offset); + resolved->is_pmem = true; + } else +#endif + { + int fput_needed; + struct file *file; + + file = fget_light(img->buf.fd, &fput_needed); + if (file == NULL) + return -EINVAL; + + ret = get_fb_info(file, resolved, + img->buf.offset); + fput_light(file, fput_needed); + if (ret < 0) + return ret; + } + + /* Check bounds */ + if (img->buf.offset + img->buf.len > + resolved->file_len) { + ret = -ESPIPE; + unresolve_buf(cont, &img->buf, resolved); + } + + break; + } + + case B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET: + ret = resolve_hwmem(cont, img, rect_2b_used, is_dst, resolved); + break; + + default: + b2r2_log_warn(cont->dev, "%s: Failed to resolve buf type %d\n", + __func__, img->buf.type); + + ret = -EINVAL; + break; + + } + + return ret; +} + +/** + * sync_buf - Synchronizes the memory occupied by an image buffer. + * + * @buf: User buffer specification + * @resolved_buf: Gathered info (physical address etc.) about buffer + * @is_dst: true if the buffer is a destination buffer, false if the buffer is a + * source buffer. + * @rect: rectangle in the image buffer that should be synced. + * NULL if the buffer is a source mask. + * @img_width: width of the complete image buffer + * @fmt: buffer format +*/ +static void sync_buf(struct b2r2_control *cont, + struct b2r2_blt_img *img, + struct b2r2_resolved_buf *resolved, + bool is_dst, + struct b2r2_blt_rect *rect) +{ + struct sync_args sa; + u32 start_phys, end_phys; + + if (B2R2_BLT_PTR_NONE == img->buf.type || + B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET == img->buf.type) + return; + + start_phys = resolved->physical_address; + end_phys = resolved->physical_address + img->buf.len; + + /* + * TODO: Very ugly. We should find out whether the memory is coherent in + * some generic way but cache handling will be rewritten soon so there + * is no use spending time on it. In the new design this will probably + * not be a problem. + */ + /* Frame buffer is coherent, at least now. */ + if (!resolved->is_pmem) { + /* + * Drain the write buffers as they are not always part of the + * coherent concept. + */ + wmb(); + + return; + } + + /* + * src_mask does not have rect. + * Also flush full buffer for planar and semiplanar YUV formats + */ + if (rect == NULL || + (img->fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR) || + (img->fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR) || + (img->fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR) || + (img->fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR) || + (img->fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR) || + (img->fmt == + B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE) || + (img->fmt == + B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE)) { + sa.start = (unsigned long)resolved->virtual_address; + sa.end = (unsigned long)resolved->virtual_address + + img->buf.len; + start_phys = resolved->physical_address; + end_phys = resolved->physical_address + img->buf.len; + } else { + /* + * buffer is not a src_mask so make use of rect when + * clean & flush caches + */ + u32 bpp; /* Bits per pixel */ + u32 pitch; + + switch (img->fmt) { + case B2R2_BLT_FMT_16_BIT_ARGB4444: /* Fall through */ + case B2R2_BLT_FMT_16_BIT_ARGB1555: /* Fall through */ + case B2R2_BLT_FMT_16_BIT_RGB565: /* Fall through */ + case B2R2_BLT_FMT_Y_CB_Y_CR: /* Fall through */ + case B2R2_BLT_FMT_CB_Y_CR_Y: + bpp = 16; + break; + case B2R2_BLT_FMT_24_BIT_RGB888: /* Fall through */ + case B2R2_BLT_FMT_24_BIT_ARGB8565: /* Fall through */ + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_24_BIT_VUY888: + bpp = 24; + break; + case B2R2_BLT_FMT_32_BIT_ARGB8888: /* Fall through */ + case B2R2_BLT_FMT_32_BIT_ABGR8888: /* Fall through */ + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + bpp = 32; + break; + default: + bpp = 12; + } + if (img->pitch == 0) + pitch = (img->width * bpp) / 8; + else + pitch = img->pitch; + + /* + * For 422I formats 2 horizontal pixels share color data. + * Thus, the x position must be aligned down to closest even + * number and width must be aligned up. + */ + { + s32 x; + s32 width; + + switch (img->fmt) { + case B2R2_BLT_FMT_Y_CB_Y_CR: /* Fall through */ + case B2R2_BLT_FMT_CB_Y_CR_Y: + x = (rect->x / 2) * 2; + width = ((rect->width + 1) / 2) * 2; + break; + default: + x = rect->x; + width = rect->width; + break; + } + + sa.start = (unsigned long)resolved->virtual_address + + rect->y * pitch + (x * bpp) / 8; + sa.end = (unsigned long)sa.start + + (rect->height - 1) * pitch + + (width * bpp) / 8; + + start_phys = resolved->physical_address + + rect->y * pitch + (x * bpp) / 8; + end_phys = start_phys + + (rect->height - 1) * pitch + + (width * bpp) / 8; + } + } + + /* + * The virtual address to a pmem buffer is retrieved from ioremap, not + * sure if it's ok to use such an address as a kernel virtual address. + * When doing it at a higher level such as dma_map_single it triggers an + * error but at lower levels such as dmac_clean_range it seems to work, + * hence the low level stuff. + */ + + if (is_dst) { + /* + * According to ARM's docs you must clean before invalidating + * (ie flush) to avoid loosing data. + */ + + /* Flush L1 cache */ +#ifdef CONFIG_SMP + flush_l1_cache_range_all_cpus(&sa); +#else + flush_l1_cache_range_curr_cpu(&sa); +#endif + + /* Flush L2 cache */ + outer_flush_range(start_phys, end_phys); + } else { + /* Clean L1 cache */ +#ifdef CONFIG_SMP + clean_l1_cache_range_all_cpus(&sa); +#else + clean_l1_cache_range_curr_cpu(&sa); +#endif + + /* Clean L2 cache */ + outer_clean_range(start_phys, end_phys); + } +} + +/** + * is_report_list_empty() - Spin lock protected check of report list + * + * @instance: The B2R2 BLT instance + */ +static bool is_report_list_empty(struct b2r2_blt_instance *instance) +{ + bool is_empty; + + mutex_lock(&instance->lock); + is_empty = list_empty(&instance->report_list); + mutex_unlock(&instance->lock); + + return is_empty; +} + +/** + * is_synching() - Spin lock protected check if synching + * + * @instance: The B2R2 BLT instance + */ +static bool is_synching(struct b2r2_blt_instance *instance) +{ + bool is_synching; + + mutex_lock(&instance->lock); + is_synching = instance->synching; + mutex_unlock(&instance->lock); + + return is_synching; +} + +/** + * inc_stat() - Spin lock protected increment of statistics variable + * + * @stat: Pointer to statistics variable that should be incremented + */ +static void inc_stat(struct b2r2_control *cont, unsigned long *stat) +{ + mutex_lock(&cont->stat_lock); + (*stat)++; + mutex_unlock(&cont->stat_lock); +} + +/** + * inc_stat() - Spin lock protected decrement of statistics variable + * + * @stat: Pointer to statistics variable that should be decremented + */ +static void dec_stat(struct b2r2_control *cont, unsigned long *stat) +{ + mutex_lock(&cont->stat_lock); + (*stat)--; + mutex_unlock(&cont->stat_lock); +} + + +#ifdef CONFIG_DEBUG_FS +/** + * sprintf_req() - Builds a string representing the request, for debug + * + * @request:Request that should be encoded into a string + * @buf: Receiving buffer + * @size: Size of receiving buffer + * + * Returns number of characters in string, excluding null terminator + */ +static int sprintf_req(struct b2r2_blt_request *request, char *buf, int size) +{ + size_t dev_size = 0; + + /* generic request info */ + dev_size += sprintf(buf + dev_size, + "instance : 0x%08lX\n", + (unsigned long) request->instance); + dev_size += sprintf(buf + dev_size, + "size : %d bytes\n", request->user_req.size); + dev_size += sprintf(buf + dev_size, + "flags : 0x%08lX\n", + (unsigned long) request->user_req.flags); + dev_size += sprintf(buf + dev_size, + "transform : %d\n", + (int) request->user_req.transform); + dev_size += sprintf(buf + dev_size, + "prio : %d\n", request->user_req.transform); + dev_size += sprintf(buf + dev_size, + "global_alpha : %d\n", + (int) request->user_req.global_alpha); + dev_size += sprintf(buf + dev_size, + "report1 : 0x%08lX\n", + (unsigned long) request->user_req.report1); + dev_size += sprintf(buf + dev_size, + "report2 : 0x%08lX\n", + (unsigned long) request->user_req.report2); + dev_size += sprintf(buf + dev_size, + "request_id : 0x%08lX\n\n", + (unsigned long) request->request_id); + + /* src info */ + dev_size += sprintf(buf + dev_size, + "src_img.fmt : %#010x\n", + request->user_req.src_img.fmt); + dev_size += sprintf(buf + dev_size, + "src_img.buf : {type=%d, hwmem_buf_name=%d, fd=%d, " + "offset=%d, len=%d}\n", + request->user_req.src_img.buf.type, + request->user_req.src_img.buf.hwmem_buf_name, + request->user_req.src_img.buf.fd, + request->user_req.src_img.buf.offset, + request->user_req.src_img.buf.len); + dev_size += sprintf(buf + dev_size, + "src_img : {width=%d, height=%d, pitch=%d}\n", + request->user_req.src_img.width, + request->user_req.src_img.height, + request->user_req.src_img.pitch); + dev_size += sprintf(buf + dev_size, + "src_mask.fmt : %#010x\n", + request->user_req.src_mask.fmt); + dev_size += sprintf(buf + dev_size, + "src_mask.buf : {type=%d, hwmem_buf_name=%d, fd=%d," + " offset=%d, len=%d}\n", + request->user_req.src_mask.buf.type, + request->user_req.src_mask.buf.hwmem_buf_name, + request->user_req.src_mask.buf.fd, + request->user_req.src_mask.buf.offset, + request->user_req.src_mask.buf.len); + dev_size += sprintf(buf + dev_size, + "src_mask : {width=%d, height=%d, pitch=%d}\n", + request->user_req.src_mask.width, + request->user_req.src_mask.height, + request->user_req.src_mask.pitch); + dev_size += sprintf(buf + dev_size, + "src_rect : {x=%d, y=%d, width=%d, height=%d}\n", + request->user_req.src_rect.x, + request->user_req.src_rect.y, + request->user_req.src_rect.width, + request->user_req.src_rect.height); + dev_size += sprintf(buf + dev_size, + "src_color : 0x%08lX\n\n", + (unsigned long) request->user_req.src_color); + + /* bg info */ + dev_size += sprintf(buf + dev_size, + "bg_img.fmt : %#010x\n", + request->user_req.bg_img.fmt); + dev_size += sprintf(buf + dev_size, + "bg_img.buf : {type=%d, hwmem_buf_name=%d, fd=%d," + " offset=%d, len=%d}\n", + request->user_req.bg_img.buf.type, + request->user_req.bg_img.buf.hwmem_buf_name, + request->user_req.bg_img.buf.fd, + request->user_req.bg_img.buf.offset, + request->user_req.bg_img.buf.len); + dev_size += sprintf(buf + dev_size, + "bg_img : {width=%d, height=%d, pitch=%d}\n", + request->user_req.bg_img.width, + request->user_req.bg_img.height, + request->user_req.bg_img.pitch); + dev_size += sprintf(buf + dev_size, + "bg_rect : {x=%d, y=%d, width=%d, height=%d}\n\n", + request->user_req.bg_rect.x, + request->user_req.bg_rect.y, + request->user_req.bg_rect.width, + request->user_req.bg_rect.height); + + /* dst info */ + dev_size += sprintf(buf + dev_size, + "dst_img.fmt : %#010x\n", + request->user_req.dst_img.fmt); + dev_size += sprintf(buf + dev_size, + "dst_img.buf : {type=%d, hwmem_buf_name=%d, fd=%d," + " offset=%d, len=%d}\n", + request->user_req.dst_img.buf.type, + request->user_req.dst_img.buf.hwmem_buf_name, + request->user_req.dst_img.buf.fd, + request->user_req.dst_img.buf.offset, + request->user_req.dst_img.buf.len); + dev_size += sprintf(buf + dev_size, + "dst_img : {width=%d, height=%d, pitch=%d}\n", + request->user_req.dst_img.width, + request->user_req.dst_img.height, + request->user_req.dst_img.pitch); + dev_size += sprintf(buf + dev_size, + "dst_rect : {x=%d, y=%d, width=%d, height=%d}\n", + request->user_req.dst_rect.x, + request->user_req.dst_rect.y, + request->user_req.dst_rect.width, + request->user_req.dst_rect.height); + dev_size += sprintf(buf + dev_size, + "dst_clip_rect : {x=%d, y=%d, width=%d, height=%d}\n", + request->user_req.dst_clip_rect.x, + request->user_req.dst_clip_rect.y, + request->user_req.dst_clip_rect.width, + request->user_req.dst_clip_rect.height); + dev_size += sprintf(buf + dev_size, + "dst_color : 0x%08lX\n\n", + (unsigned long) request->user_req.dst_color); + + dev_size += sprintf(buf + dev_size, + "src_resolved.physical : 0x%08lX\n", + (unsigned long) request->src_resolved. + physical_address); + dev_size += sprintf(buf + dev_size, + "src_resolved.virtual : 0x%08lX\n", + (unsigned long) request->src_resolved.virtual_address); + dev_size += sprintf(buf + dev_size, + "src_resolved.filep : 0x%08lX\n", + (unsigned long) request->src_resolved.filep); + dev_size += sprintf(buf + dev_size, + "src_resolved.filep_physical_start : 0x%08lX\n", + (unsigned long) request->src_resolved. + file_physical_start); + dev_size += sprintf(buf + dev_size, + "src_resolved.filep_virtual_start : 0x%08lX\n", + (unsigned long) request->src_resolved.file_virtual_start); + dev_size += sprintf(buf + dev_size, + "src_resolved.file_len : %d\n\n", + request->src_resolved.file_len); + + dev_size += sprintf(buf + dev_size, + "src_mask_resolved.physical : 0x%08lX\n", + (unsigned long) request->src_mask_resolved. + physical_address); + dev_size += sprintf(buf + dev_size, + "src_mask_resolved.virtual : 0x%08lX\n", + (unsigned long) request->src_mask_resolved.virtual_address); + dev_size += sprintf(buf + dev_size, + "src_mask_resolved.filep : 0x%08lX\n", + (unsigned long) request->src_mask_resolved.filep); + dev_size += sprintf(buf + dev_size, + "src_mask_resolved.filep_physical_start : 0x%08lX\n", + (unsigned long) request->src_mask_resolved. + file_physical_start); + dev_size += sprintf(buf + dev_size, + "src_mask_resolved.filep_virtual_start : 0x%08lX\n", + (unsigned long) request->src_mask_resolved. + file_virtual_start); + dev_size += sprintf(buf + dev_size, + "src_mask_resolved.file_len : %d\n\n", + request->src_mask_resolved.file_len); + + dev_size += sprintf(buf + dev_size, + "dst_resolved.physical : 0x%08lX\n", + (unsigned long) request->dst_resolved. + physical_address); + dev_size += sprintf(buf + dev_size, + "dst_resolved.virtual : 0x%08lX\n", + (unsigned long) request->dst_resolved.virtual_address); + dev_size += sprintf(buf + dev_size, + "dst_resolved.filep : 0x%08lX\n", + (unsigned long) request->dst_resolved.filep); + dev_size += sprintf(buf + dev_size, + "dst_resolved.filep_physical_start : 0x%08lX\n", + (unsigned long) request->dst_resolved. + file_physical_start); + dev_size += sprintf(buf + dev_size, + "dst_resolved.filep_virtual_start : 0x%08lX\n", + (unsigned long) request->dst_resolved.file_virtual_start); + dev_size += sprintf(buf + dev_size, + "dst_resolved.file_len : %d\n\n", + request->dst_resolved.file_len); + + return dev_size; +} + +/** + * debugfs_b2r2_blt_request_read() - Implements debugfs read for B2R2 register + * + * @filp: File pointer + * @buf: User space buffer + * @count: Number of bytes to read + * @f_pos: File position + * + * Returns number of bytes read or negative error code + */ +static int debugfs_b2r2_blt_request_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + size_t dev_size = 0; + int ret = 0; + char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL); + struct b2r2_control *cont = filp->f_dentry->d_inode->i_private; + + if (Buf == NULL) { + ret = -ENOMEM; + goto out; + } + + dev_size = sprintf_req(&cont->debugfs_latest_request, Buf, + sizeof(char) * 4096); + + /* No more to read if offset != 0 */ + if (*f_pos > dev_size) + goto out; + + if (*f_pos + count > dev_size) + count = dev_size - *f_pos; + + if (copy_to_user(buf, Buf, count)) + ret = -EINVAL; + *f_pos += count; + ret = count; + +out: + if (Buf != NULL) + kfree(Buf); + return ret; +} + +/** + * debugfs_b2r2_blt_request_fops - File operations for B2R2 request debugfs + */ +static const struct file_operations debugfs_b2r2_blt_request_fops = { + .owner = THIS_MODULE, + .read = debugfs_b2r2_blt_request_read, +}; + +/** + * struct debugfs_reg - Represents a B2R2 node "register" + * + * @name: Register name + * @offset: Offset within the node + */ +struct debugfs_reg { + const char name[30]; + u32 offset; +}; + +/** + * debugfs_node_regs - Array with all the registers in a B2R2 node, for debug + */ +static const struct debugfs_reg debugfs_node_regs[] = { + {"GROUP0.B2R2_NIP", offsetof(struct b2r2_link_list, GROUP0.B2R2_NIP)}, + {"GROUP0.B2R2_CIC", offsetof(struct b2r2_link_list, GROUP0.B2R2_CIC)}, + {"GROUP0.B2R2_INS", offsetof(struct b2r2_link_list, GROUP0.B2R2_INS)}, + {"GROUP0.B2R2_ACK", offsetof(struct b2r2_link_list, GROUP0.B2R2_ACK)}, + + {"GROUP1.B2R2_TBA", offsetof(struct b2r2_link_list, GROUP1.B2R2_TBA)}, + {"GROUP1.B2R2_TTY", offsetof(struct b2r2_link_list, GROUP1.B2R2_TTY)}, + {"GROUP1.B2R2_TXY", offsetof(struct b2r2_link_list, GROUP1.B2R2_TXY)}, + {"GROUP1.B2R2_TSZ", offsetof(struct b2r2_link_list, GROUP1.B2R2_TSZ)}, + + {"GROUP2.B2R2_S1CF", offsetof(struct b2r2_link_list, GROUP2.B2R2_S1CF)}, + {"GROUP2.B2R2_S2CF", offsetof(struct b2r2_link_list, GROUP2.B2R2_S2CF)}, + + {"GROUP3.B2R2_SBA", offsetof(struct b2r2_link_list, GROUP3.B2R2_SBA)}, + {"GROUP3.B2R2_STY", offsetof(struct b2r2_link_list, GROUP3.B2R2_STY)}, + {"GROUP3.B2R2_SXY", offsetof(struct b2r2_link_list, GROUP3.B2R2_SXY)}, + {"GROUP3.B2R2_SSZ", offsetof(struct b2r2_link_list, GROUP3.B2R2_SSZ)}, + + {"GROUP4.B2R2_SBA", offsetof(struct b2r2_link_list, GROUP4.B2R2_SBA)}, + {"GROUP4.B2R2_STY", offsetof(struct b2r2_link_list, GROUP4.B2R2_STY)}, + {"GROUP4.B2R2_SXY", offsetof(struct b2r2_link_list, GROUP4.B2R2_SXY)}, + {"GROUP4.B2R2_SSZ", offsetof(struct b2r2_link_list, GROUP4.B2R2_SSZ)}, + + {"GROUP5.B2R2_SBA", offsetof(struct b2r2_link_list, GROUP5.B2R2_SBA)}, + {"GROUP5.B2R2_STY", offsetof(struct b2r2_link_list, GROUP5.B2R2_STY)}, + {"GROUP5.B2R2_SXY", offsetof(struct b2r2_link_list, GROUP5.B2R2_SXY)}, + {"GROUP5.B2R2_SSZ", offsetof(struct b2r2_link_list, GROUP5.B2R2_SSZ)}, + + {"GROUP6.B2R2_CWO", offsetof(struct b2r2_link_list, GROUP6.B2R2_CWO)}, + {"GROUP6.B2R2_CWS", offsetof(struct b2r2_link_list, GROUP6.B2R2_CWS)}, + + {"GROUP7.B2R2_CCO", offsetof(struct b2r2_link_list, GROUP7.B2R2_CCO)}, + {"GROUP7.B2R2_CML", offsetof(struct b2r2_link_list, GROUP7.B2R2_CML)}, + + {"GROUP8.B2R2_FCTL", offsetof(struct b2r2_link_list, GROUP8.B2R2_FCTL)}, + {"GROUP8.B2R2_PMK", offsetof(struct b2r2_link_list, GROUP8.B2R2_PMK)}, + + {"GROUP9.B2R2_RSF", offsetof(struct b2r2_link_list, GROUP9.B2R2_RSF)}, + {"GROUP9.B2R2_RZI", offsetof(struct b2r2_link_list, GROUP9.B2R2_RZI)}, + {"GROUP9.B2R2_HFP", offsetof(struct b2r2_link_list, GROUP9.B2R2_HFP)}, + {"GROUP9.B2R2_VFP", offsetof(struct b2r2_link_list, GROUP9.B2R2_VFP)}, + + {"GROUP10.B2R2_RSF", offsetof(struct b2r2_link_list, GROUP10.B2R2_RSF)}, + {"GROUP10.B2R2_RZI", offsetof(struct b2r2_link_list, GROUP10.B2R2_RZI)}, + {"GROUP10.B2R2_HFP", offsetof(struct b2r2_link_list, GROUP10.B2R2_HFP)}, + {"GROUP10.B2R2_VFP", offsetof(struct b2r2_link_list, GROUP10.B2R2_VFP)}, + + {"GROUP11.B2R2_FF0", offsetof(struct b2r2_link_list, + GROUP11.B2R2_FF0)}, + {"GROUP11.B2R2_FF1", offsetof(struct b2r2_link_list, + GROUP11.B2R2_FF1)}, + {"GROUP11.B2R2_FF2", offsetof(struct b2r2_link_list, + GROUP11.B2R2_FF2)}, + {"GROUP11.B2R2_FF3", offsetof(struct b2r2_link_list, + GROUP11.B2R2_FF3)}, + + {"GROUP12.B2R2_KEY1", offsetof(struct b2r2_link_list, + GROUP12.B2R2_KEY1)}, + {"GROUP12.B2R2_KEY2", offsetof(struct b2r2_link_list, + GROUP12.B2R2_KEY2)}, + + {"GROUP13.B2R2_XYL", offsetof(struct b2r2_link_list, GROUP13.B2R2_XYL)}, + {"GROUP13.B2R2_XYP", offsetof(struct b2r2_link_list, GROUP13.B2R2_XYP)}, + + {"GROUP14.B2R2_SAR", offsetof(struct b2r2_link_list, GROUP14.B2R2_SAR)}, + {"GROUP14.B2R2_USR", offsetof(struct b2r2_link_list, GROUP14.B2R2_USR)}, + + {"GROUP15.B2R2_VMX0", offsetof(struct b2r2_link_list, + GROUP15.B2R2_VMX0)}, + {"GROUP15.B2R2_VMX1", offsetof(struct b2r2_link_list, + GROUP15.B2R2_VMX1)}, + {"GROUP15.B2R2_VMX2", offsetof(struct b2r2_link_list, + GROUP15.B2R2_VMX2)}, + {"GROUP15.B2R2_VMX3", offsetof(struct b2r2_link_list, + GROUP15.B2R2_VMX3)}, + + {"GROUP16.B2R2_VMX0", offsetof(struct b2r2_link_list, + GROUP16.B2R2_VMX0)}, + {"GROUP16.B2R2_VMX1", offsetof(struct b2r2_link_list, + GROUP16.B2R2_VMX1)}, + {"GROUP16.B2R2_VMX2", offsetof(struct b2r2_link_list, + GROUP16.B2R2_VMX2)}, + {"GROUP16.B2R2_VMX3", offsetof(struct b2r2_link_list, + GROUP16.B2R2_VMX3)}, +}; + +/** + * debugfs_b2r2_blt_stat_read() - Implements debugfs read for B2R2 BLT + * statistics + * + * @filp: File pointer + * @buf: User space buffer + * @count: Number of bytes to read + * @f_pos: File position + * + * Returns number of bytes read or negative error code + */ +static int debugfs_b2r2_blt_stat_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + size_t dev_size = 0; + int ret = 0; + char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL); + struct b2r2_control *cont = filp->f_dentry->d_inode->i_private; + + if (Buf == NULL) { + ret = -ENOMEM; + goto out; + } + + mutex_lock(&cont->stat_lock); + dev_size += sprintf(Buf + dev_size, "Added jobs : %lu\n", + cont->stat_n_jobs_added); + dev_size += sprintf(Buf + dev_size, "Released jobs : %lu\n", + cont->stat_n_jobs_released); + dev_size += sprintf(Buf + dev_size, "Jobs in report list : %lu\n", + cont->stat_n_jobs_in_report_list); + dev_size += sprintf(Buf + dev_size, "Clients in open : %lu\n", + cont->stat_n_in_open); + dev_size += sprintf(Buf + dev_size, "Clients in release : %lu\n", + cont->stat_n_in_release); + dev_size += sprintf(Buf + dev_size, "Clients in blt : %lu\n", + cont->stat_n_in_blt); + dev_size += sprintf(Buf + dev_size, " synch : %lu\n", + cont->stat_n_in_blt_synch); + dev_size += sprintf(Buf + dev_size, " add : %lu\n", + cont->stat_n_in_blt_add); + dev_size += sprintf(Buf + dev_size, " wait : %lu\n", + cont->stat_n_in_blt_wait); + dev_size += sprintf(Buf + dev_size, "Clients in synch 0 : %lu\n", + cont->stat_n_in_synch_0); + dev_size += sprintf(Buf + dev_size, "Clients in synch job : %lu\n", + cont->stat_n_in_synch_job); + dev_size += sprintf(Buf + dev_size, "Clients in query_cap : %lu\n", + cont->stat_n_in_query_cap); + mutex_unlock(&cont->stat_lock); + + /* No more to read if offset != 0 */ + if (*f_pos > dev_size) + goto out; + + if (*f_pos + count > dev_size) + count = dev_size - *f_pos; + + if (copy_to_user(buf, Buf, count)) + ret = -EINVAL; + *f_pos += count; + ret = count; + +out: + if (Buf != NULL) + kfree(Buf); + return ret; +} + +/** + * debugfs_b2r2_blt_stat_fops() - File operations for B2R2 BLT + * statistics debugfs + */ +static const struct file_operations debugfs_b2r2_blt_stat_fops = { + .owner = THIS_MODULE, + .read = debugfs_b2r2_blt_stat_read, +}; +#endif + +static void init_tmp_bufs(struct b2r2_control *cont) +{ + int i = 0; + + for (i = 0; i < (sizeof(cont->tmp_bufs) / sizeof(struct tmp_buf)); + i++) { + cont->tmp_bufs[i].buf.virt_addr = dma_alloc_coherent( + cont->dev, MAX_TMP_BUF_SIZE, + &cont->tmp_bufs[i].buf.phys_addr, GFP_DMA); + if (cont->tmp_bufs[i].buf.virt_addr != NULL) + cont->tmp_bufs[i].buf.size = MAX_TMP_BUF_SIZE; + else { + b2r2_log_err(cont->dev, "%s: Failed to allocate temp " + "buffer %i\n", __func__, i); + cont->tmp_bufs[i].buf.size = 0; + } + } +} + +static void destroy_tmp_bufs(struct b2r2_control *cont) +{ + int i = 0; + + for (i = 0; i < MAX_TMP_BUFS_NEEDED; i++) { + if (cont->tmp_bufs[i].buf.size != 0) { + dma_free_coherent(cont->dev, + cont->tmp_bufs[i].buf.size, + cont->tmp_bufs[i].buf.virt_addr, + cont->tmp_bufs[i].buf.phys_addr); + + cont->tmp_bufs[i].buf.size = 0; + } + } +} + +/** + * b2r2_blt_module_init() - Module init function + * + * Returns 0 if OK else negative error code + */ +int b2r2_blt_module_init(struct b2r2_control *cont) +{ + int ret; + + mutex_init(&cont->stat_lock); + + /* Register b2r2 driver */ + cont->miscdev.minor = MISC_DYNAMIC_MINOR; + cont->miscdev.name = cont->name; + cont->miscdev.fops = &b2r2_blt_fops; + + ret = misc_register(&cont->miscdev); + if (ret) { + printk(KERN_WARNING "%s: registering misc device fails\n", + __func__); + goto b2r2_misc_register_fail; + } + + cont->dev = cont->miscdev.this_device; + dev_set_drvdata(cont->dev, cont); + +#ifdef CONFIG_B2R2_GENERIC + /* Initialize generic path */ + b2r2_generic_init(cont); +#endif + /* Initialize node splitter */ + ret = b2r2_node_split_init(cont); + if (ret) { + printk(KERN_WARNING "%s: node split init fails\n", __func__); + goto b2r2_node_split_init_fail; + } + + b2r2_log_info(cont->dev, "%s: device registered\n", __func__); + + /* + * FIXME: This stuff should be done before the first requests i.e. + * before misc_register, but they need the device which is not + * available until after misc_register. + */ + cont->dev->coherent_dma_mask = 0xFFFFFFFF; + init_tmp_bufs(cont); + ret = b2r2_filters_init(cont); + if (ret) { + b2r2_log_warn(cont->dev, "%s: failed to init filters\n", + __func__); + goto b2r2_filter_init_fail; + } + + /* Initialize memory allocator */ + ret = b2r2_mem_init(cont, B2R2_HEAP_SIZE, + 4, sizeof(struct b2r2_node)); + if (ret) { + printk(KERN_WARNING "%s: initializing B2R2 memhandler fails\n", + __func__); + goto b2r2_mem_init_fail; + } + +#ifdef CONFIG_DEBUG_FS + /* Register debug fs */ + if (cont->debugfs_root_dir) { + debugfs_create_file("last_request", 0666, + cont->debugfs_root_dir, + cont, &debugfs_b2r2_blt_request_fops); + debugfs_create_file("stats", 0666, + cont->debugfs_root_dir, + cont, &debugfs_b2r2_blt_stat_fops); + } +#endif + + b2r2_ctl[cont->id] = cont; + b2r2_log_info(cont->dev, "%s: done\n", __func__); + + return ret; + +b2r2_mem_init_fail: + b2r2_filters_exit(cont); +b2r2_filter_init_fail: + b2r2_node_split_exit(cont); +b2r2_node_split_init_fail: +#ifdef CONFIG_B2R2_GENERIC + b2r2_generic_exit(cont); +#endif + misc_deregister(&cont->miscdev); +b2r2_misc_register_fail: + return ret; +} + +/** + * b2r2_module_exit() - Module exit function + */ +void b2r2_blt_module_exit(struct b2r2_control *cont) +{ + if (cont) { + b2r2_log_info(cont->dev, "%s\n", __func__); +#ifdef CONFIG_DEBUG_FS + if (cont->debugfs_root_dir) { + debugfs_remove_recursive(cont->debugfs_root_dir); + cont->debugfs_root_dir = NULL; + } +#endif + b2r2_mem_exit(cont); + destroy_tmp_bufs(cont); + b2r2_ctl[cont->id] = NULL; + misc_deregister(&cont->miscdev); + b2r2_node_split_exit(cont); +#if defined(CONFIG_B2R2_GENERIC) + b2r2_generic_exit(cont); +#endif + b2r2_filters_exit(cont); + } +} + +MODULE_AUTHOR("Robert Fekete <robert.fekete@stericsson.com>"); +MODULE_DESCRIPTION("ST-Ericsson B2R2 Blitter module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/b2r2/b2r2_core.c b/drivers/video/b2r2/b2r2_core.c new file mode 100644 index 00000000000..629633a7888 --- /dev/null +++ b/drivers/video/b2r2/b2r2_core.c @@ -0,0 +1,2819 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 core driver + * + * Author: Robert Fekete <robert.fekete@stericsson.com> + * Author: Paul Wannback + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +/* + * TODO: Clock address from platform data + * Platform data should have string id instead of numbers + * b2r2_remove, some type of runtime problem when kernel hacking + * debug features on + * + * Is there already a priority list in kernel? + * Is it possible to handle clock using clock framework? + * uTimeOut, use mdelay instead? + * Measure performance + * + * Exchange our home-cooked ref count with kernel kref? See + * http://lwn.net/Articles/336224/ + * + * B2R2: + * Source fill 2 bug + * Check with Symbian? + */ + +/* include file */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/uaccess.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#ifdef CONFIG_DEBUG_FS +#include <linux/debugfs.h> +#endif +#include <linux/jiffies.h> +#include <linux/timer.h> +#include <linux/clk.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/err.h> + +#include "b2r2_internal.h" +#include "b2r2_core.h" +#include "b2r2_global.h" +#include "b2r2_structures.h" +#include "b2r2_internal.h" +#include "b2r2_profiler_api.h" +#include "b2r2_timing.h" +#include "b2r2_debug.h" + +/** + * B2R2_DRIVER_TIMEOUT_VALUE - Busy loop timeout after soft reset + */ +#define B2R2_DRIVER_TIMEOUT_VALUE (1500) + +/** + * B2R2_CLK_FLAG - Value to write into clock reg to turn clock on + */ +#define B2R2_CLK_FLAG (0x125) + +/** + * DEBUG_CHECK_ADDREF_RELEASE - Define this to enable addref / release debug + */ +#define DEBUG_CHECK_ADDREF_RELEASE 1 + +#ifdef CONFIG_DEBUG_FS +/** + * HANDLE_TIMEOUTED_JOBS - Define this to check jobs for timeout and cancel them + */ +#define HANDLE_TIMEOUTED_JOBS 1 +#endif + +/** + * B2R2_CLOCK_ALWAYS_ON - Define this to disable power save clock turn off + */ +/* #define B2R2_CLOCK_ALWAYS_ON 1 */ + +/** + * START_SENTINEL - Watch guard to detect job overwrites + */ +#define START_SENTINEL 0xBABEDEEA + +/** + * STOP_SENTINEL - Watch guard to detect job overwrites + */ +#define END_SENTINEL 0xDADBDCDD + +/** + * B2R2_CORE_LOWEST_PRIO - Lowest prio allowed + */ +#define B2R2_CORE_LOWEST_PRIO -19 +/** + * B2R2_CORE_HIGHEST_PRIO - Highest prio allowed + */ +#define B2R2_CORE_HIGHEST_PRIO 20 + +/** + * B2R2_DOMAIN_DISABLE - + */ +#define B2R2_DOMAIN_DISABLE_TIMEOUT (HZ/100) + +/** + * B2R2_REGULATOR_RETRY_COUNT - + */ +#define B2R2_REGULATOR_RETRY_COUNT 10 + +/** + * B2R2 Hardware defines below + */ + +/* - BLT_AQ_CTL */ +#define B2R2_AQ_Enab (0x80000000) +#define B2R2_AQ_PRIOR_0 (0x0) +#define B2R2_AQ_PRIOR_1 (0x1) +#define B2R2_AQ_PRIOR_2 (0x2) +#define B2R2_AQ_PRIOR_3 (0x3) +#define B2R2_AQ_NODE_REPEAT_INT (0x100000) +#define B2R2_AQ_STOP_INT (0x200000) +#define B2R2_AQ_LNA_REACH_INT (0x400000) +#define B2R2_AQ_COMPLETED_INT (0x800000) + +/* - BLT_CTL */ +#define B2R2BLT_CTLGLOBAL_soft_reset (0x80000000) +#define B2R2BLT_CTLStep_By_Step (0x20000000) +#define B2R2BLT_CTLBig_not_little (0x10000000) +#define B2R2BLT_CTLMask (0xb0000000) +#define B2R2BLT_CTLTestMask (0xb0000000) +#define B2R2BLT_CTLInitialValue (0x0) +#define B2R2BLT_CTLAccessType (INITIAL_TEST) +#define B2R2BLT_CTL (0xa00) + +/* - BLT_ITS */ +#define B2R2BLT_ITSRLD_ERROR (0x80000000) +#define B2R2BLT_ITSAQ4_Node_Notif (0x8000000) +#define B2R2BLT_ITSAQ4_Node_repeat (0x4000000) +#define B2R2BLT_ITSAQ4_Stopped (0x2000000) +#define B2R2BLT_ITSAQ4_LNA_Reached (0x1000000) +#define B2R2BLT_ITSAQ3_Node_Notif (0x800000) +#define B2R2BLT_ITSAQ3_Node_repeat (0x400000) +#define B2R2BLT_ITSAQ3_Stopped (0x200000) +#define B2R2BLT_ITSAQ3_LNA_Reached (0x100000) +#define B2R2BLT_ITSAQ2_Node_Notif (0x80000) +#define B2R2BLT_ITSAQ2_Node_repeat (0x40000) +#define B2R2BLT_ITSAQ2_Stopped (0x20000) +#define B2R2BLT_ITSAQ2_LNA_Reached (0x10000) +#define B2R2BLT_ITSAQ1_Node_Notif (0x8000) +#define B2R2BLT_ITSAQ1_Node_repeat (0x4000) +#define B2R2BLT_ITSAQ1_Stopped (0x2000) +#define B2R2BLT_ITSAQ1_LNA_Reached (0x1000) +#define B2R2BLT_ITSCQ2_Repaced (0x80) +#define B2R2BLT_ITSCQ2_Node_Notif (0x40) +#define B2R2BLT_ITSCQ2_retriggered (0x20) +#define B2R2BLT_ITSCQ2_completed (0x10) +#define B2R2BLT_ITSCQ1_Repaced (0x8) +#define B2R2BLT_ITSCQ1_Node_Notif (0x4) +#define B2R2BLT_ITSCQ1_retriggered (0x2) +#define B2R2BLT_ITSCQ1_completed (0x1) +#define B2R2BLT_ITSMask (0x8ffff0ff) +#define B2R2BLT_ITSTestMask (0x8ffff0ff) +#define B2R2BLT_ITSInitialValue (0x0) +#define B2R2BLT_ITSAccessType (INITIAL_TEST) +#define B2R2BLT_ITS (0xa04) + +/* - BLT_STA1 */ +#define B2R2BLT_STA1BDISP_IDLE (0x1) +#define B2R2BLT_STA1Mask (0x1) +#define B2R2BLT_STA1TestMask (0x1) +#define B2R2BLT_STA1InitialValue (0x1) +#define B2R2BLT_STA1AccessType (INITIAL_TEST) +#define B2R2BLT_STA1 (0xa08) + + +#ifdef DEBUG_CHECK_ADDREF_RELEASE + +/** + * struct addref_release - Represents one addref or release. Used + * to debug addref / release problems + * + * @addref: true if this represents an addref else it represents + * a release. + * @job: The job that was referenced + * @caller: The caller of the addref or release + * @ref_count: The job reference count after addref / release + */ +struct addref_release { + bool addref; + struct b2r2_core_job *job; + const char *caller; + int ref_count; +}; + +#endif + +/** + * struct b2r2_core - Administration data for B2R2 core + * + * @lock: Spin lock protecting the b2r2_core structure and the B2R2 HW + * @hw: B2R2 registers memory mapped + * @pmu_b2r2_clock: Control of B2R2 clock + * @log_dev: Device used for logging via dev_... functions + * + * @prio_queue: Queue of jobs sorted in priority order + * @active_jobs: Array containing pointer to zero or one job per queue + * @n_active_jobs: Number of active jobs + * @jiffies_last_active: jiffie value when adding last active job + * @jiffies_last_irq: jiffie value when last irq occured + * @timeout_work: Work structure for timeout work + * + * @next_job_id: Contains the job id that will be assigned to the next + * added job. + * + * @clock_request_count: When non-zero, clock is on + * @clock_off_timer: Kernel timer to handle delayed turn off of clock + * + * @work_queue: Work queue to handle done jobs (callbacks) and timeouts in + * non-interrupt context. + * + * @stat_n_irq: Number of interrupts (statistics) + * @stat_n_jobs_added: Number of jobs added (statistics) + * @stat_n_jobs_removed: Number of jobs removed (statistics) + * @stat_n_jobs_in_prio_list: Number of jobs in prio list (statistics) + * + * @debugfs_root_dir: Root directory for B2R2 debugfs + * + * @ar: Circular array of addref / release debug structs + * @ar_write: Where next write will occur + * @ar_read: First valid place to read. When ar_read == ar_write then + * the array is empty. + */ +struct b2r2_core { + spinlock_t lock; + + struct b2r2_memory_map *hw; + + u8 op_size; + u8 ch_size; + u8 pg_size; + u8 mg_size; + u16 min_req_time; + int irq; + + char name[16]; + struct device *dev; + + struct list_head prio_queue; + + struct b2r2_core_job *active_jobs[B2R2_CORE_QUEUE_NO_OF]; + unsigned long n_active_jobs; + + unsigned long jiffies_last_active; + unsigned long jiffies_last_irq; +#ifdef HANDLE_TIMEOUTED_JOBS + struct delayed_work timeout_work; +#endif + int next_job_id; + + unsigned long clock_request_count; + struct timer_list clock_off_timer; + + struct workqueue_struct *work_queue; + + /* Statistics */ + unsigned long stat_n_irq; + unsigned long stat_n_jobs_added; + unsigned long stat_n_jobs_removed; + + unsigned long stat_n_jobs_in_prio_list; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root_dir; + struct dentry *debugfs_core_root_dir; + struct dentry *debugfs_regs_dir; +#endif + +#ifdef DEBUG_CHECK_ADDREF_RELEASE + /* Tracking release bug...*/ + struct addref_release ar[100]; + int ar_write; + int ar_read; +#endif + + /* Power management variables */ + struct mutex domain_lock; + struct delayed_work domain_disable_work; + + /* + * We need to keep track of both the number of domain_enable/disable() + * calls and whether the power was actually turned off, since the + * power off is done in a delayed job. + */ + bool domain_enabled; + int domain_request_count; + + struct clk *b2r2_clock; + struct regulator *b2r2_reg; + + struct b2r2_control *control; +}; + +/** + * b2r2_core - Quick link to administration data for B2R2 + */ +static struct b2r2_core *b2r2_core[B2R2_MAX_NBR_DEVICES]; + +/* Local functions */ +static void check_prio_list(struct b2r2_core *core, bool atomic); +static void clear_interrupts(struct b2r2_core *core); +static void trigger_job(struct b2r2_core *core, struct b2r2_core_job *job); +static void exit_job_list(struct b2r2_core *core, + struct list_head *job_list); +static int get_next_job_id(struct b2r2_core *core); +static void job_work_function(struct work_struct *ptr); +static void init_job(struct b2r2_core_job *job); +static void insert_into_prio_list(struct b2r2_core *core, + struct b2r2_core_job *job); +static struct b2r2_core_job *find_job_in_list(int job_id, + struct list_head *list); +static struct b2r2_core_job *find_job_in_active_jobs(struct b2r2_core *core, + int job_id); +static struct b2r2_core_job *find_tag_in_list(struct b2r2_core *core, + int tag, struct list_head *list); +static struct b2r2_core_job *find_tag_in_active_jobs(struct b2r2_core *core, + int tag); + +static int domain_enable(struct b2r2_core *core); +static void domain_disable(struct b2r2_core *core); + +static void stop_queue(enum b2r2_core_queue queue); + +#ifdef HANDLE_TIMEOUTED_JOBS +static void printk_regs(struct b2r2_core *core); +static int hw_reset(struct b2r2_core *core); +static void timeout_work_function(struct work_struct *ptr); +#endif + +static void reset_hw_timer(struct b2r2_core_job *job); +static void start_hw_timer(struct b2r2_core_job *job); +static void stop_hw_timer(struct b2r2_core *core, + struct b2r2_core_job *job); + +static int init_hw(struct b2r2_core *core); +static void exit_hw(struct b2r2_core *core); + +/* Tracking release bug... */ +#ifdef DEBUG_CHECK_ADDREF_RELEASE +/** + * ar_add() - Adds an addref or a release to the array + * + * @core: The b2r2 core entity + * @job: The job that has been referenced + * @caller: The caller of addref / release + * @addref: true if it is an addref else false for release + */ +static void ar_add(struct b2r2_core *core, struct b2r2_core_job *job, + const char *caller, bool addref) +{ + core->ar[core->ar_write].addref = addref; + core->ar[core->ar_write].job = job; + core->ar[core->ar_write].caller = caller; + core->ar[core->ar_write].ref_count = job->ref_count; + core->ar_write = (core->ar_write + 1) % + ARRAY_SIZE(core->ar); + if (core->ar_write == core->ar_read) + core->ar_read = (core->ar_read + 1) % + ARRAY_SIZE(core->ar); +} + +/** + * sprintf_ar() - Writes all addref / release to a string buffer + * + * @core: The b2r2 core entity + * @buf: Receiving character bufefr + * @job: Which job to write or NULL for all + * + * NOTE! No buffer size check!! + */ +static char *sprintf_ar(struct b2r2_core *core, char *buf, + struct b2r2_core_job *job) +{ + int i; + int size = 0; + + for (i = core->ar_read; i != core->ar_write; + i = (i + 1) % ARRAY_SIZE(core->ar)) { + struct addref_release *ar = &core->ar[i]; + if (!job || job == ar->job) + size += sprintf(buf + size, + "%s on %p from %s, ref = %d\n", + ar->addref ? "addref" : "release", + ar->job, ar->caller, ar->ref_count); + } + + return buf; +} + +/** + * printk_ar() - Writes all addref / release using dev_info + * + * @core: The b2r2 core entity + * @job: Which job to write or NULL for all + */ +static void printk_ar(struct b2r2_core *core, struct b2r2_core_job *job) +{ + int i; + + for (i = core->ar_read; i != core->ar_write; + i = (i + 1) % ARRAY_SIZE(core->ar)) { + struct addref_release *ar = &core->ar[i]; + if (!job || job == ar->job) + b2r2_log_info(core->dev, "%s on %p from %s," + " ref = %d\n", + ar->addref ? "addref" : "release", + ar->job, ar->caller, ar->ref_count); + } +} +#endif + +/** + * internal_job_addref() - Increments the reference count for a job + * + * @core: The b2r2 core entity + * @job: Which job to increment reference count for + * @caller: Name of function calling addref (for debug) + * + * Note that core->lock _must_ be held + */ +static void internal_job_addref(struct b2r2_core *core, + struct b2r2_core_job *job, const char *caller) +{ + u32 ref_count; + + b2r2_log_info(core->dev, "%s (%p, %p) (from %s)\n", + __func__, core, job, caller); + + /* Sanity checks */ + BUG_ON(job == NULL); + + if (job->start_sentinel != START_SENTINEL || + job->end_sentinel != END_SENTINEL || + job->ref_count == 0 || job->ref_count > 10) { + b2r2_log_info(core->dev, "%s: (%p, %p) start=%X end=%X " + "ref_count=%d\n", __func__, core, job, + job->start_sentinel, job->end_sentinel, + job->ref_count); + + /* Something is wrong, print the addref / release array */ +#ifdef DEBUG_CHECK_ADDREF_RELEASE + printk_ar(core, NULL); +#endif + } + + + BUG_ON(job->start_sentinel != START_SENTINEL); + BUG_ON(job->end_sentinel != END_SENTINEL); + + /* Do the actual reference count increment */ + ref_count = ++job->ref_count; + +#ifdef DEBUG_CHECK_ADDREF_RELEASE + /* Keep track of addref / release */ + ar_add(core, job, caller, true); +#endif + + b2r2_log_info(core->dev, "%s called from %s (%p, %p): Ref Count is " + "%d\n", __func__, caller, core, job, job->ref_count); +} + +/** + * internal_job_release() - Decrements the reference count for a job + * + * @core: The b2r2 core entity + * @job: Which job to decrement reference count for + * @caller: Name of function calling release (for debug) + * + * Returns true if job_release should be called by caller + * (reference count reached zero). + * + * Note that core->lock _must_ be held + */ +static bool internal_job_release(struct b2r2_core *core, + struct b2r2_core_job *job, const char *caller) +{ + u32 ref_count; + bool call_release = false; + + /* Sanity checks */ + BUG_ON(job == NULL); + + b2r2_log_info(core->dev, "%s (%p, %p) (from %s)\n", + __func__, core, job, caller); + + if (job->start_sentinel != START_SENTINEL || + job->end_sentinel != END_SENTINEL || + job->ref_count == 0 || job->ref_count > 10) { + b2r2_log_info(core->dev, "%s: (%p, %p) start=%X end=%X " + "ref_count=%d\n", __func__, core, job, + job->start_sentinel, job->end_sentinel, + job->ref_count); + +#ifdef DEBUG_CHECK_ADDREF_RELEASE + printk_ar(core, NULL); +#endif + } + + BUG_ON(job->start_sentinel != START_SENTINEL); + BUG_ON(job->end_sentinel != END_SENTINEL); + BUG_ON(job->ref_count == 0 || job->ref_count > 10); + + /* Do the actual decrement */ + ref_count = --job->ref_count; +#ifdef DEBUG_CHECK_ADDREF_RELEASE + ar_add(core, job, caller, false); +#endif + b2r2_log_info(core->dev, "%s called from %s (%p, %p) Ref Count is " + "%d\n", __func__, caller, core, job, ref_count); + + if (!ref_count && job->release) { + call_release = true; + /* Job will now cease to exist */ + job->start_sentinel = 0xFFFFFFFF; + job->end_sentinel = 0xFFFFFFFF; + } + return call_release; +} + + + +/* Exported functions */ + +/** + * core->lock _must_ _NOT_ be held when calling this function + */ +void b2r2_core_job_addref(struct b2r2_core_job *job, const char *caller) +{ + unsigned long flags; + struct b2r2_blt_instance *instance; + struct b2r2_core *core; + + instance = (struct b2r2_blt_instance *) job->tag; + core = instance->control->data; + + spin_lock_irqsave(&core->lock, flags); + internal_job_addref(core, job, caller); + spin_unlock_irqrestore(&core->lock, flags); +} + +/** + * core->lock _must_ _NOT_ be held when calling this function + */ +void b2r2_core_job_release(struct b2r2_core_job *job, const char *caller) +{ + unsigned long flags; + bool call_release = false; + struct b2r2_blt_instance *instance; + struct b2r2_core *core; + + instance = (struct b2r2_blt_instance *) job->tag; + core = instance->control->data; + + spin_lock_irqsave(&core->lock, flags); + call_release = internal_job_release(core, job, caller); + spin_unlock_irqrestore(&core->lock, flags); + + if (call_release) + job->release(job); +} + +/** + * core->lock _must_ _NOT_ be held when calling this function + */ +int b2r2_core_job_add(struct b2r2_control *control, + struct b2r2_core_job *job) +{ + unsigned long flags; + struct b2r2_core *core = control->data; + + b2r2_log_info(core->dev, "%s (%p, %p)\n", __func__, control, job); + + /* Enable B2R2 */ + domain_enable(core); + + spin_lock_irqsave(&core->lock, flags); + core->stat_n_jobs_added++; + + /* Initialise internal job data */ + init_job(job); + + /* Initial reference, should be released by caller of this function */ + job->ref_count = 1; + + /* Insert job into prio list */ + insert_into_prio_list(core, job); + + /* Check if we can dispatch job */ + check_prio_list(core, false); + spin_unlock_irqrestore(&core->lock, flags); + + return 0; +} + +/** + * core->lock _must_ _NOT_ be held when calling this function + */ +struct b2r2_core_job *b2r2_core_job_find(struct b2r2_control *control, + int job_id) +{ + unsigned long flags; + struct b2r2_core_job *job; + struct b2r2_core *core = control->data; + + b2r2_log_info(core->dev, "%s (%p, %d)\n", __func__, control, job_id); + + spin_lock_irqsave(&core->lock, flags); + /* Look through prio queue */ + job = find_job_in_list(job_id, &core->prio_queue); + + if (!job) + job = find_job_in_active_jobs(core, job_id); + + spin_unlock_irqrestore(&core->lock, flags); + + return job; +} + +/** + * core->lock _must_ _NOT_ be held when calling this function + */ +struct b2r2_core_job *b2r2_core_job_find_first_with_tag( + struct b2r2_control *control, int tag) +{ + unsigned long flags; + struct b2r2_core_job *job; + struct b2r2_core *core = control->data; + + b2r2_log_info(core->dev, "%s (%p, %d)\n", __func__, control, tag); + + spin_lock_irqsave(&core->lock, flags); + /* Look through prio queue */ + job = find_tag_in_list(core, tag, &core->prio_queue); + + if (!job) + job = find_tag_in_active_jobs(core, tag); + + spin_unlock_irqrestore(&core->lock, flags); + + return job; +} + +/** + * is_job_done() - Spin lock protected check if job is done + * + * @job: Job to check + * + * Returns true if job is done or cancelled + * + * core->lock must _NOT_ be held when calling this function + */ +static bool is_job_done(struct b2r2_core_job *job) +{ + unsigned long flags; + bool job_is_done; + struct b2r2_blt_instance *instance; + struct b2r2_core *core; + + instance = (struct b2r2_blt_instance *) job->tag; + core = instance->control->data; + + spin_lock_irqsave(&core->lock, flags); + job_is_done = + job->job_state != B2R2_CORE_JOB_QUEUED && + job->job_state != B2R2_CORE_JOB_RUNNING; + spin_unlock_irqrestore(&core->lock, flags); + + return job_is_done; +} + +/** + * b2r2_core_job_wait() + * + * @job: + * + * core->lock _must_ _NOT_ be held when calling this function + */ +int b2r2_core_job_wait(struct b2r2_core_job *job) +{ + int ret = 0; + struct b2r2_blt_instance *instance; + struct b2r2_core *core; + + instance = (struct b2r2_blt_instance *) job->tag; + core = instance->control->data; + + b2r2_log_info(core->dev, "%s (%p)\n", __func__, job); + /* Check that we have the job */ + if (job->job_state == B2R2_CORE_JOB_IDLE) { + /* Never or not queued */ + b2r2_log_info(core->dev, "%s: Job not queued\n", __func__); + return -ENOENT; + } + + /* Wait for the job to be done */ + ret = wait_event_interruptible( + job->event, + is_job_done(job)); + + if (ret) + b2r2_log_warn(core->dev, + "%s: wait_event_interruptible returns %d state is %d", + __func__, ret, job->job_state); + return ret; +} + +/** + * cancel_job() - Cancels a job (removes it from prio list or active jobs) and + * calls the job callback + * + * @job: Job to cancel + * + * Returns true if the job was found and cancelled + * + * core->lock must be held when calling this function + */ +static bool cancel_job(struct b2r2_core *core, struct b2r2_core_job *job) +{ + bool found_job = false; + bool job_was_active = false; + + /* Remove from prio list */ + if (job->job_state == B2R2_CORE_JOB_QUEUED) { + list_del_init(&job->list); + found_job = true; + } + + /* Remove from active jobs */ + if (!found_job && core->n_active_jobs > 0) { + int i; + + /* Look for timeout:ed jobs and put them in tmp list */ + for (i = 0; i < ARRAY_SIZE(core->active_jobs); i++) { + if (core->active_jobs[i] == job) { + stop_queue((enum b2r2_core_queue)i); + stop_hw_timer(core, job); + core->active_jobs[i] = NULL; + core->n_active_jobs--; + found_job = true; + job_was_active = true; + } + } + } + + /* Handle done list & callback */ + if (found_job) { + /* Job is canceled */ + job->job_state = B2R2_CORE_JOB_CANCELED; + + queue_work(core->work_queue, &job->work); + + /* Statistics */ + if (!job_was_active) + core->stat_n_jobs_in_prio_list--; + + } + + return found_job; +} + +/* core->lock _must_ _NOT_ be held when calling this function */ +int b2r2_core_job_cancel(struct b2r2_core_job *job) +{ + unsigned long flags; + int ret = 0; + struct b2r2_blt_instance *instance; + struct b2r2_core *core; + + instance = (struct b2r2_blt_instance *) job->tag; + core = instance->control->data; + + b2r2_log_info(core->dev, "%s (%p) (%d)\n", + __func__, job, job->job_state); + /* Check that we have the job */ + if (job->job_state == B2R2_CORE_JOB_IDLE) { + /* Never or not queued */ + b2r2_log_info(core->dev, "%s: Job not queued\n", __func__); + return -ENOENT; + } + + /* Remove from prio list */ + spin_lock_irqsave(&core->lock, flags); + cancel_job(core, job); + spin_unlock_irqrestore(&core->lock, flags); + + return ret; +} + +/* LOCAL FUNCTIONS BELOW */ + +/** + * domain_disable_work_function() + * + * @core: The b2r2 core entity + */ +static void domain_disable_work_function(struct work_struct *work) +{ + struct delayed_work *twork = to_delayed_work(work); + struct b2r2_core *core = container_of( + twork, struct b2r2_core, domain_disable_work); + + if (!mutex_trylock(&core->domain_lock)) + return; + + if (core->domain_request_count == 0) { + exit_hw(core); + clk_disable(core->b2r2_clock); + regulator_disable(core->b2r2_reg); + core->domain_enabled = false; + } + + mutex_unlock(&core->domain_lock); +} + +/** + * domain_enable() + * + * @core: The b2r2 core entity + */ +static int domain_enable(struct b2r2_core *core) +{ + mutex_lock(&core->domain_lock); + core->domain_request_count++; + + if (!core->domain_enabled) { + int retry = 0; + int ret; +again: + /* + * Since regulator_enable() may sleep we have to handle + * interrupts. + */ + ret = regulator_enable(core->b2r2_reg); + if ((ret == -EAGAIN) && + ((retry++) < B2R2_REGULATOR_RETRY_COUNT)) + goto again; + else if (ret < 0) + goto regulator_enable_failed; + + clk_enable(core->b2r2_clock); + if (init_hw(core) < 0) + goto init_hw_failed; + core->domain_enabled = true; + } + + mutex_unlock(&core->domain_lock); + + return 0; + +init_hw_failed: + b2r2_log_err(core->dev, + "%s: Could not initialize hardware!\n", __func__); + + clk_disable(core->b2r2_clock); + + if (regulator_disable(core->b2r2_reg) < 0) + b2r2_log_err(core->dev, "%s: regulator_disable failed!\n", + __func__); + +regulator_enable_failed: + core->domain_request_count--; + mutex_unlock(&core->domain_lock); + + return -EFAULT; +} + +/** + * domain_disable() + * + * @core: The b2r2 core entity + */ +static void domain_disable(struct b2r2_core *core) +{ + mutex_lock(&core->domain_lock); + + if (core->domain_request_count == 0) { + b2r2_log_err(core->dev, + "%s: Unbalanced domain_disable()\n", __func__); + } else { + core->domain_request_count--; + + /* Cancel any existing work */ + cancel_delayed_work_sync(&core->domain_disable_work); + + /* Add a work to disable the power and clock after a delay */ + queue_delayed_work(core->work_queue, &core->domain_disable_work, + B2R2_DOMAIN_DISABLE_TIMEOUT); + } + + mutex_unlock(&core->domain_lock); +} + +/** + * stop_queue() - Stops the specified queue. + */ +static void stop_queue(enum b2r2_core_queue queue) +{ + /* TODO: Implement! If this function is not implemented canceled jobs + * will use b2r2 which is a waste of resources. Not stopping jobs will + * also screw up the hardware timing, the job the canceled job + * intrerrupted (if any) will be billed for the time between the point + * where the job is cancelled and when it stops. */ +} + +/** + * exit_job_list() - Empties a job queue by canceling the jobs + * + * @core: The b2r2 core entity + * + * core->lock _must_ be held when calling this function + */ +static void exit_job_list(struct b2r2_core *core, + struct list_head *job_queue) +{ + while (!list_empty(job_queue)) { + struct b2r2_core_job *job = + list_entry(job_queue->next, + struct b2r2_core_job, + list); + /* Add reference to prevent job from disappearing + in the middle of our work, released below */ + internal_job_addref(core, job, __func__); + + cancel_job(core, job); + + /* Matching release to addref above */ + internal_job_release(core, job, __func__); + + } +} + +/** + * get_next_job_id() - Return a new job id. + * + * @core: The b2r2 core entity + */ +static int get_next_job_id(struct b2r2_core *core) +{ + int job_id; + + if (core->next_job_id < 1) + core->next_job_id = 1; + job_id = core->next_job_id++; + + return job_id; +} + +/** + * job_work_function() - Work queue function that calls callback(s) and + * checks if B2R2 can accept a new job + * + * @ptr: Pointer to work struct (embedded in struct b2r2_core_job) + */ +static void job_work_function(struct work_struct *ptr) +{ + unsigned long flags; + struct b2r2_core_job *job = + container_of(ptr, struct b2r2_core_job, work); + struct b2r2_blt_instance *instance; + struct b2r2_core *core; + + instance = (struct b2r2_blt_instance *) job->tag; + core = instance->control->data; + + /* Disable B2R2 */ + domain_disable(core); + + /* Release resources */ + if (job->release_resources) + job->release_resources(job, false); + + spin_lock_irqsave(&core->lock, flags); + + /* Dispatch a new job if possible */ + check_prio_list(core, false); + + spin_unlock_irqrestore(&core->lock, flags); + + /* Tell the client */ + if (job->callback) + job->callback(job); + + /* Drop our reference, matches the + addref in handle_queue_event or b2r2_core_job_cancel */ + b2r2_core_job_release(job, __func__); +} + +#ifdef HANDLE_TIMEOUTED_JOBS +/** + * timeout_work_function() - Work queue function that checks for + * timeout:ed jobs. B2R2 might silently refuse + * to execute some jobs, i.e. SRC2 fill + * + * @ptr: Pointer to work struct (embedded in struct b2r2_core) + * + */ +static void timeout_work_function(struct work_struct *ptr) +{ + unsigned long flags; + struct list_head job_list; + struct delayed_work *twork = to_delayed_work(ptr); + struct b2r2_core *core = container_of(twork, struct b2r2_core, + timeout_work); + + INIT_LIST_HEAD(&job_list); + + /* Cancel all jobs if too long time since last irq */ + spin_lock_irqsave(&core->lock, flags); + if (core->n_active_jobs > 0) { + unsigned long diff = + (long) jiffies - (long) core->jiffies_last_irq; + if (diff > HZ/2) { + /* Active jobs and more than a second since last irq! */ + int i; + + /* Look for timeout:ed jobs and put them in tmp list. + * It's important that the application queues are + * killed in order of decreasing priority */ + for (i = 0; i < ARRAY_SIZE(core->active_jobs); i++) { + struct b2r2_core_job *job = + core->active_jobs[i]; + + if (job) { + stop_hw_timer(core, job); + core->active_jobs[i] = NULL; + core->n_active_jobs--; + list_add_tail(&job->list, &job_list); + } + } + + /* Print the B2R2 register and reset B2R2 */ + printk_regs(core); + hw_reset(core); + } + } + spin_unlock_irqrestore(&core->lock, flags); + + /* Handle timeout:ed jobs */ + spin_lock_irqsave(&core->lock, flags); + while (!list_empty(&job_list)) { + struct b2r2_core_job *job = + list_entry(job_list.next, + struct b2r2_core_job, + list); + + b2r2_log_warn(core->dev, "%s: Job timeout\n", __func__); + + list_del_init(&job->list); + + /* Job is cancelled */ + job->job_state = B2R2_CORE_JOB_CANCELED; + + /* Handle done */ + wake_up_interruptible(&job->event); + + /* Job callbacks handled via work queue */ + queue_work(core->work_queue, &job->work); + } + + /* Requeue delayed work */ + if (core->n_active_jobs) + queue_delayed_work( + core->work_queue, + &core->timeout_work, HZ/2); + + spin_unlock_irqrestore(&core->lock, flags); +} +#endif + +/** + * reset_hw_timer() - Resets a job's hardware timer. Must be called before + * the timer is used. + * + * @job: Pointer to job struct + * + * core->lock _must_ be held when calling this function + */ +static void reset_hw_timer(struct b2r2_core_job *job) +{ + job->nsec_active_in_hw = 0; +} + +/** + * start_hw_timer() - Times how long a job spends in hardware (active). + * Should be called immediatly before starting the + * hardware. + * + * @job: Pointer to job struct + * + * core->lock _must_ be held when calling this function + */ +static void start_hw_timer(struct b2r2_core_job *job) +{ + job->hw_start_time = b2r2_get_curr_nsec(); +} + +/** + * stop_hw_timer() - Times how long a job spends in hardware (active). + * Should be called immediatly after the hardware has + * finished. + * + * @core: The b2r2 core entity + * @job: Pointer to job struct + * + * core->lock _must_ be held when calling this function + */ +static void stop_hw_timer(struct b2r2_core *core, struct b2r2_core_job *job) +{ + /* Assumes only app queues are used, which is the case right now. */ + /* Not 100% accurate. When a higher prio job interrupts a lower prio job it does + so after the current node of the low prio job has finished. Currently we can not + sense when the actual switch takes place so the time reported for a job that + interrupts a lower prio job will on average contain the time it takes to process + half a node in the lower prio job in addition to the time it takes to process the + job's own nodes. This could possibly be solved by adding node notifications but + that would involve a significant amount of work and consume system resources due + to the extra interrupts. */ + /* If a job takes more than ~2s (absolute time, including idleing in the hardware) + the state of the hardware timer will be corrupted and it will not report valid + values until b2r2 becomes idle (no active jobs on any queues). The maximum length + can possibly be increased by using 64 bit integers. */ + + int i; + + u32 stop_time_raw = b2r2_get_curr_nsec(); + /* We'll add an offset to all positions in time to make the current time equal to + 0xFFFFFFFF. This way we can compare positions in time to each other without having + to wory about wrapping (so long as all positions in time are in the past). */ + u32 stop_time = 0xFFFFFFFF; + u32 time_pos_offset = 0xFFFFFFFF - stop_time_raw; + u32 nsec_in_hw = stop_time - (job->hw_start_time + time_pos_offset); + job->nsec_active_in_hw += (s32)nsec_in_hw; + + /* Check if we have delayed the start of higher prio jobs. Can happen as queue + switching only can be done between nodes. */ + for (i = (int)job->queue - 1; i >= (int)B2R2_CORE_QUEUE_AQ1; i--) { + struct b2r2_core_job *queue_active_job = core->active_jobs[i]; + if (NULL == queue_active_job) + continue; + + queue_active_job->hw_start_time = stop_time_raw; + } + + /* Check if the job has stolen time from lower prio jobs */ + for (i = (int)job->queue + 1; i < B2R2_NUM_APPLICATIONS_QUEUES; i++) { + struct b2r2_core_job *queue_active_job = core->active_jobs[i]; + u32 queue_active_job_hw_start_time; + + if (NULL == queue_active_job) + continue; + + queue_active_job_hw_start_time = + queue_active_job->hw_start_time + + time_pos_offset; + + if (queue_active_job_hw_start_time < stop_time) { + u32 queue_active_job_nsec_in_hw = stop_time - + queue_active_job_hw_start_time; + u32 num_stolen_nsec = min(queue_active_job_nsec_in_hw, + nsec_in_hw); + + queue_active_job->nsec_active_in_hw -= (s32)num_stolen_nsec; + + nsec_in_hw -= num_stolen_nsec; + stop_time -= num_stolen_nsec; + } + + if (0 == nsec_in_hw) + break; + } +} + +/** + * init_job() - Initializes a job structure from filled in client data. + * Reference count will be set to 1 + * + * @job: Job to initialize + */ +static void init_job(struct b2r2_core_job *job) +{ + struct b2r2_blt_instance *instance; + struct b2r2_core *core; + + instance = (struct b2r2_blt_instance *) job->tag; + core = instance->control->data; + + job->start_sentinel = START_SENTINEL; + job->end_sentinel = END_SENTINEL; + + /* Get a job id*/ + job->job_id = get_next_job_id(core); + + /* Job is idle, never queued */ + job->job_state = B2R2_CORE_JOB_IDLE; + + /* Initialize internal data */ + INIT_LIST_HEAD(&job->list); + init_waitqueue_head(&job->event); + INIT_WORK(&job->work, job_work_function); + + /* Map given prio to B2R2 queues */ + if (job->prio < B2R2_CORE_LOWEST_PRIO) + job->prio = B2R2_CORE_LOWEST_PRIO; + else if (job->prio > B2R2_CORE_HIGHEST_PRIO) + job->prio = B2R2_CORE_HIGHEST_PRIO; + + if (job->prio > 10) { + job->queue = B2R2_CORE_QUEUE_AQ1; + job->interrupt_context = + (B2R2BLT_ITSAQ1_LNA_Reached); + job->control = (B2R2_AQ_Enab | B2R2_AQ_PRIOR_3); + } else if (job->prio > 0) { + job->queue = B2R2_CORE_QUEUE_AQ2; + job->interrupt_context = + (B2R2BLT_ITSAQ2_LNA_Reached); + job->control = (B2R2_AQ_Enab | B2R2_AQ_PRIOR_2); + } else if (job->prio > -10) { + job->queue = B2R2_CORE_QUEUE_AQ3; + job->interrupt_context = + (B2R2BLT_ITSAQ3_LNA_Reached); + job->control = (B2R2_AQ_Enab | B2R2_AQ_PRIOR_1); + } else { + job->queue = B2R2_CORE_QUEUE_AQ4; + job->interrupt_context = + (B2R2BLT_ITSAQ4_LNA_Reached); + job->control = (B2R2_AQ_Enab | B2R2_AQ_PRIOR_0); + } +} + +/** + * clear_interrupts() - Disables all interrupts + * + * core->lock _must_ be held + */ +static void clear_interrupts(struct b2r2_core *core) +{ + writel(0x0, &core->hw->BLT_ITM0); + writel(0x0, &core->hw->BLT_ITM1); + writel(0x0, &core->hw->BLT_ITM2); + writel(0x0, &core->hw->BLT_ITM3); +} + +/** + * insert_into_prio_list() - Inserts the job into the sorted list of jobs. + * The list is sorted by priority. + * + * @core: The b2r2 core entity + * @job: Job to insert + * + * core->lock _must_ be held + */ +static void insert_into_prio_list(struct b2r2_core *core, + struct b2r2_core_job *job) +{ + /* Ref count is increased when job put in list, + should be released when job is removed from list */ + internal_job_addref(core, job, __func__); + + core->stat_n_jobs_in_prio_list++; + + /* Sort in the job */ + if (list_empty(&core->prio_queue)) + list_add_tail(&job->list, &core->prio_queue); + else { + struct b2r2_core_job *first_job = list_entry( + core->prio_queue.next, + struct b2r2_core_job, list); + struct b2r2_core_job *last_job = list_entry( + core->prio_queue.prev, + struct b2r2_core_job, list); + + if (job->prio > first_job->prio) + list_add(&job->list, &core->prio_queue); + else if (job->prio <= last_job->prio) + list_add_tail(&job->list, &core->prio_queue); + else { + /* We need to find where to put it */ + struct list_head *ptr; + + list_for_each(ptr, &core->prio_queue) { + struct b2r2_core_job *list_job = + list_entry(ptr, struct b2r2_core_job, + list); + if (job->prio > list_job->prio) { + list_add_tail(&job->list, + &list_job->list); + break; + } + } + } + } + /* The job is now queued */ + job->job_state = B2R2_CORE_JOB_QUEUED; +} + +/** + * check_prio_list() - Checks if the first job(s) in the prio list can + * be dispatched to B2R2 + * + * @core: The b2r2 core entity + * @atomic: true if in atomic context (i.e. interrupt context) + * + * core->lock _must_ be held + */ +static void check_prio_list(struct b2r2_core *core, bool atomic) +{ + bool dispatched_job; + int n_dispatched = 0; + struct b2r2_core_job *job; + + do { + dispatched_job = false; + + /* Do we have anything in our prio list? */ + if (list_empty(&core->prio_queue)) + break; + + /* The first job waiting */ + job = list_first_entry(&core->prio_queue, + struct b2r2_core_job, list); + + /* Is the B2R2 queue available? */ + if (core->active_jobs[job->queue] != NULL) + break; + + /* Can we acquire resources? */ + if (!job->acquire_resources || + job->acquire_resources(job, atomic) == 0) { + /* Ok to dispatch job */ + + /* Remove from list */ + list_del_init(&job->list); + + /* The job is now active */ + core->active_jobs[job->queue] = job; + core->n_active_jobs++; + job->jiffies = jiffies; + core->jiffies_last_active = jiffies; + + /* Kick off B2R2 */ + trigger_job(core, job); + dispatched_job = true; + n_dispatched++; + +#ifdef HANDLE_TIMEOUTED_JOBS + /* Check in one half second if it hangs */ + queue_delayed_work(core->work_queue, + &core->timeout_work, HZ/2); +#endif + } else { + /* No resources */ + if (!atomic && core->n_active_jobs == 0) { + b2r2_log_warn(core->dev, + "%s: No resource", __func__); + cancel_job(core, job); + } + } + } while (dispatched_job); + + core->stat_n_jobs_in_prio_list -= n_dispatched; +} + +/** + * find_job_in_list() - Finds job with job_id in list + * + * @jobid: Job id to find + * @list: List to find job id in + * + * Reference count will be incremented for found job. + * + * core->lock _must_ be held + */ +static struct b2r2_core_job *find_job_in_list(int job_id, + struct list_head *list) +{ + struct list_head *ptr; + + list_for_each(ptr, list) { + struct b2r2_core_job *job = list_entry( + ptr, struct b2r2_core_job, list); + if (job->job_id == job_id) { + struct b2r2_blt_instance *instance = + (struct b2r2_blt_instance *) job->tag; + struct b2r2_core *core = instance->control->data; + /* Increase reference count, should be released by + the caller of b2r2_core_job_find */ + internal_job_addref(core, job, __func__); + return job; + } + } + return NULL; +} + +/** + * find_job_in_active_jobs() - Finds job in active job queues + * + * @core: The b2r2 core entity + * @job_id: Job id to find + * + * Reference count will be incremented for found job. + * + * core->lock _must_ be held + */ +static struct b2r2_core_job *find_job_in_active_jobs(struct b2r2_core *core, + int job_id) +{ + int i; + struct b2r2_core_job *found_job = NULL; + + if (core->n_active_jobs) { + for (i = 0; i < ARRAY_SIZE(core->active_jobs); i++) { + struct b2r2_core_job *job = core->active_jobs[i]; + + if (job && job->job_id == job_id) { + internal_job_addref(core, job, __func__); + found_job = job; + break; + } + } + } + return found_job; +} + +/** + * find_tag_in_list() - Finds first job with tag in list + * + * @tag: Tag to find + * @list: List to find job id in + * + * Reference count will be incremented for found job. + * + * core->lock must be held + */ +static struct b2r2_core_job *find_tag_in_list(struct b2r2_core *core, + int tag, struct list_head *list) +{ + struct list_head *ptr; + + list_for_each(ptr, list) { + struct b2r2_core_job *job = + list_entry(ptr, struct b2r2_core_job, list); + if (job->tag == tag) { + /* Increase reference count, should be released by + the caller of b2r2_core_job_find */ + internal_job_addref(core, job, __func__); + return job; + } + } + return NULL; +} + +/** + * find_tag_in_active_jobs() - Finds job with tag in active job queues + * + * @tag: Tag to find + * + * Reference count will be incremented for found job. + * + * core->lock must be held + */ +static struct b2r2_core_job *find_tag_in_active_jobs(struct b2r2_core *core, + int tag) +{ + int i; + struct b2r2_core_job *found_job = NULL; + + if (core->n_active_jobs) { + for (i = 0; i < ARRAY_SIZE(core->active_jobs); i++) { + struct b2r2_core_job *job = core->active_jobs[i]; + + if (job && job->tag == tag) { + internal_job_addref(core, job, __func__); + found_job = job; + break; + } + } + } + return found_job; +} + + +#ifdef HANDLE_TIMEOUTED_JOBS +/** + * hw_reset() - Resets B2R2 hardware + * + * core->lock must be held + */ +static int hw_reset(struct b2r2_core *core) +{ + u32 uTimeOut = B2R2_DRIVER_TIMEOUT_VALUE; + + /* Tell B2R2 to reset */ + writel(readl(&core->hw->BLT_CTL) | B2R2BLT_CTLGLOBAL_soft_reset, + &core->hw->BLT_CTL); + writel(0x00000000, &core->hw->BLT_CTL); + + b2r2_log_info(core->dev, "wait for B2R2 to be idle..\n"); + + /** Wait for B2R2 to be idle (on a timeout rather than while loop) */ + while ((uTimeOut > 0) && + ((readl(&core->hw->BLT_STA1) & + B2R2BLT_STA1BDISP_IDLE) == 0x0)) + uTimeOut--; + + if (uTimeOut == 0) { + b2r2_log_warn(core->dev, + "error-> after software reset B2R2 is not idle\n"); + return -EAGAIN; + } + + return 0; + +} +#endif + +/** + * trigger_job() - Put job in B2R2 HW queue + * + * @job: Job to trigger + * + * core->lock must be held + */ +static void trigger_job(struct b2r2_core *core, struct b2r2_core_job *job) +{ + /* Debug prints */ + b2r2_log_info(core->dev, "queue 0x%x\n", job->queue); + b2r2_log_info(core->dev, "BLT TRIG_IP 0x%x (first node)\n", + job->first_node_address); + b2r2_log_info(core->dev, "BLT LNA_CTL 0x%x (last node)\n", + job->last_node_address); + b2r2_log_info(core->dev, "BLT TRIG_CTL 0x%x\n", job->control); + b2r2_log_info(core->dev, "BLT PACE_CTL 0x%x\n", job->pace_control); + + reset_hw_timer(job); + job->job_state = B2R2_CORE_JOB_RUNNING; + + /* Enable interrupt */ + writel(readl(&core->hw->BLT_ITM0) | job->interrupt_context, + &core->hw->BLT_ITM0); + + writel(min_t(u8, max_t(u8, core->op_size, B2R2_PLUG_OPCODE_SIZE_8), + B2R2_PLUG_OPCODE_SIZE_64), &core->hw->PLUGS1_OP2); + writel(min_t(u8, core->ch_size, B2R2_PLUG_CHUNK_SIZE_128), + &core->hw->PLUGS1_CHZ); + writel(min_t(u8, core->mg_size, B2R2_PLUG_MESSAGE_SIZE_128) | + (core->min_req_time << 16), &core->hw->PLUGS1_MSZ); + writel(min_t(u8, core->pg_size, B2R2_PLUG_PAGE_SIZE_256), + &core->hw->PLUGS1_PGZ); + + writel(min_t(u8, max_t(u8, core->op_size, B2R2_PLUG_OPCODE_SIZE_8), + B2R2_PLUG_OPCODE_SIZE_64), &core->hw->PLUGS2_OP2); + writel(min_t(u8, core->ch_size, B2R2_PLUG_CHUNK_SIZE_128), + &core->hw->PLUGS2_CHZ); + writel(min_t(u8, core->mg_size, B2R2_PLUG_MESSAGE_SIZE_128) | + (core->min_req_time << 16), &core->hw->PLUGS2_MSZ); + writel(min_t(u8, core->pg_size, B2R2_PLUG_PAGE_SIZE_256), + &core->hw->PLUGS2_PGZ); + + writel(min_t(u8, max_t(u8, core->op_size, B2R2_PLUG_OPCODE_SIZE_8), + B2R2_PLUG_OPCODE_SIZE_64), &core->hw->PLUGS3_OP2); + writel(min_t(u8, core->ch_size, B2R2_PLUG_CHUNK_SIZE_128), + &core->hw->PLUGS3_CHZ); + writel(min_t(u8, core->mg_size, B2R2_PLUG_MESSAGE_SIZE_128) | + (core->min_req_time << 16), &core->hw->PLUGS3_MSZ); + writel(min_t(u8, core->pg_size, B2R2_PLUG_PAGE_SIZE_256), + &core->hw->PLUGS3_PGZ); + + writel(min_t(u8, max_t(u8, core->op_size, B2R2_PLUG_OPCODE_SIZE_8), + B2R2_PLUG_OPCODE_SIZE_64), &core->hw->PLUGT_OP2); + writel(min_t(u8, core->ch_size, B2R2_PLUG_CHUNK_SIZE_128), + &core->hw->PLUGT_CHZ); + writel(min_t(u8, core->mg_size, B2R2_PLUG_MESSAGE_SIZE_128) | + (core->min_req_time << 16), &core->hw->PLUGT_MSZ); + writel(min_t(u8, core->pg_size, B2R2_PLUG_PAGE_SIZE_256), + &core->hw->PLUGT_PGZ); + + /* B2R2 kicks off when LNA is written, LNA write must be last! */ + switch (job->queue) { + case B2R2_CORE_QUEUE_CQ1: + writel(job->first_node_address, &core->hw->BLT_CQ1_TRIG_IP); + writel(job->control, &core->hw->BLT_CQ1_TRIG_CTL); + writel(job->pace_control, &core->hw->BLT_CQ1_PACE_CTL); + break; + + case B2R2_CORE_QUEUE_CQ2: + writel(job->first_node_address, &core->hw->BLT_CQ2_TRIG_IP); + writel(job->control, &core->hw->BLT_CQ2_TRIG_CTL); + writel(job->pace_control, &core->hw->BLT_CQ2_PACE_CTL); + break; + + case B2R2_CORE_QUEUE_AQ1: + writel(job->control, &core->hw->BLT_AQ1_CTL); + writel(job->first_node_address, &core->hw->BLT_AQ1_IP); + wmb(); + start_hw_timer(job); + writel(job->last_node_address, &core->hw->BLT_AQ1_LNA); + break; + + case B2R2_CORE_QUEUE_AQ2: + writel(job->control, &core->hw->BLT_AQ2_CTL); + writel(job->first_node_address, &core->hw->BLT_AQ2_IP); + wmb(); + start_hw_timer(job); + writel(job->last_node_address, &core->hw->BLT_AQ2_LNA); + break; + + case B2R2_CORE_QUEUE_AQ3: + writel(job->control, &core->hw->BLT_AQ3_CTL); + writel(job->first_node_address, &core->hw->BLT_AQ3_IP); + wmb(); + start_hw_timer(job); + writel(job->last_node_address, &core->hw->BLT_AQ3_LNA); + break; + + case B2R2_CORE_QUEUE_AQ4: + writel(job->control, &core->hw->BLT_AQ4_CTL); + writel(job->first_node_address, &core->hw->BLT_AQ4_IP); + wmb(); + start_hw_timer(job); + writel(job->last_node_address, &core->hw->BLT_AQ4_LNA); + break; + + /** Handle the default case */ + default: + break; + + } /* end switch */ + +} + +/** + * handle_queue_event() - Handles interrupt event for specified B2R2 queue + * + * @queue: Queue to handle event for + * + * core->lock must be held + */ +static void handle_queue_event(struct b2r2_core *core, + enum b2r2_core_queue queue) +{ + struct b2r2_core_job *job; + + job = core->active_jobs[queue]; + if (job) { + if (job->job_state != B2R2_CORE_JOB_RUNNING) + /* Should be running + Severe error. TBD */ + b2r2_log_warn(core->dev, + "%s: Job is not running", __func__); + + stop_hw_timer(core, job); + + /* Remove from queue */ + BUG_ON(core->n_active_jobs == 0); + core->active_jobs[queue] = NULL; + core->n_active_jobs--; + } + + if (!job) { + /* No job, error? */ + b2r2_log_warn(core->dev, "%s: No job", __func__); + return; + } + + + /* Atomic context release resources, release resources will + be called again later from process context (work queue) */ + if (job->release_resources) + job->release_resources(job, true); + + /* Job is done */ + job->job_state = B2R2_CORE_JOB_DONE; + + /* Handle done */ + wake_up_interruptible(&job->event); + + /* Dispatch to work queue to handle callbacks */ + queue_work(core->work_queue, &job->work); +} + +/** + * process_events() - Handles interrupt events + * + * @status: Contents of the B2R2 ITS register + */ +static void process_events(struct b2r2_core *core, u32 status) +{ + u32 mask = 0xF; + u32 disable_itm_mask = 0; + + b2r2_log_info(core->dev, "Enters process_events\n"); + b2r2_log_info(core->dev, "status 0x%x\n", status); + + /* Composition queue 1 */ + if (status & mask) { + handle_queue_event(core, B2R2_CORE_QUEUE_CQ1); + disable_itm_mask |= mask; + } + mask <<= 4; + + /* Composition queue 2 */ + if (status & mask) { + handle_queue_event(core, B2R2_CORE_QUEUE_CQ2); + disable_itm_mask |= mask; + } + mask <<= 8; + + /* Application queue 1 */ + if (status & mask) { + handle_queue_event(core, B2R2_CORE_QUEUE_AQ1); + disable_itm_mask |= mask; + } + mask <<= 4; + + /* Application queue 2 */ + if (status & mask) { + handle_queue_event(core, B2R2_CORE_QUEUE_AQ2); + disable_itm_mask |= mask; + } + mask <<= 4; + + /* Application queue 3 */ + if (status & mask) { + handle_queue_event(core, B2R2_CORE_QUEUE_AQ3); + disable_itm_mask |= mask; + } + mask <<= 4; + + /* Application queue 4 */ + if (status & mask) { + handle_queue_event(core, B2R2_CORE_QUEUE_AQ4); + disable_itm_mask |= mask; + } + + /* Clear received interrupt flags */ + writel(status, &core->hw->BLT_ITS); + /* Disable handled interrupts */ + writel(readl(&core->hw->BLT_ITM0) & ~disable_itm_mask, + &core->hw->BLT_ITM0); + + b2r2_log_info(core->dev, "Returns process_events\n"); +} + +/** + * b2r2_irq_handler() - B2R2 interrupt handler + * + * @irq: Interrupt number (not used) + * @x: ??? (Not used) + */ +static irqreturn_t b2r2_irq_handler(int irq, void *x) +{ + unsigned long flags; + struct b2r2_core* core = (struct b2r2_core *) x; + + /* Spin lock is need in irq handler (SMP) */ + spin_lock_irqsave(&core->lock, flags); + + /* Make sure that we have a clock */ + + /* Remember time for last irq (for timeout mgmt) */ + core->jiffies_last_irq = jiffies; + core->stat_n_irq++; + + /* Handle the interrupt(s) */ + process_events(core, readl(&core->hw->BLT_ITS)); + + /* Check if we can dispatch new jobs */ + check_prio_list(core, true); + + spin_unlock_irqrestore(&core->lock, flags); + + return IRQ_HANDLED; +} + + +#ifdef CONFIG_DEBUG_FS +/** + * struct debugfs_reg - Represents one B2R2 register in debugfs + * + * @name: Register name + * @offset: Byte offset in B2R2 for register + */ +struct debugfs_reg { + const char name[30]; + u32 offset; +}; + +/** + * debugfs_regs - Array of B2R2 debugfs registers + */ +static const struct debugfs_reg debugfs_regs[] = { + {"BLT_SSBA17", offsetof(struct b2r2_memory_map, BLT_SSBA17)}, + {"BLT_SSBA18", offsetof(struct b2r2_memory_map, BLT_SSBA18)}, + {"BLT_SSBA19", offsetof(struct b2r2_memory_map, BLT_SSBA19)}, + {"BLT_SSBA20", offsetof(struct b2r2_memory_map, BLT_SSBA20)}, + {"BLT_SSBA21", offsetof(struct b2r2_memory_map, BLT_SSBA21)}, + {"BLT_SSBA22", offsetof(struct b2r2_memory_map, BLT_SSBA22)}, + {"BLT_SSBA23", offsetof(struct b2r2_memory_map, BLT_SSBA23)}, + {"BLT_SSBA24", offsetof(struct b2r2_memory_map, BLT_SSBA24)}, + {"BLT_STBA5", offsetof(struct b2r2_memory_map, BLT_STBA5)}, + {"BLT_STBA6", offsetof(struct b2r2_memory_map, BLT_STBA6)}, + {"BLT_STBA7", offsetof(struct b2r2_memory_map, BLT_STBA7)}, + {"BLT_STBA8", offsetof(struct b2r2_memory_map, BLT_STBA8)}, + {"BLT_CTL", offsetof(struct b2r2_memory_map, BLT_CTL)}, + {"BLT_ITS", offsetof(struct b2r2_memory_map, BLT_ITS)}, + {"BLT_STA1", offsetof(struct b2r2_memory_map, BLT_STA1)}, + {"BLT_SSBA1", offsetof(struct b2r2_memory_map, BLT_SSBA1)}, + {"BLT_SSBA2", offsetof(struct b2r2_memory_map, BLT_SSBA2)}, + {"BLT_SSBA3", offsetof(struct b2r2_memory_map, BLT_SSBA3)}, + {"BLT_SSBA4", offsetof(struct b2r2_memory_map, BLT_SSBA4)}, + {"BLT_SSBA5", offsetof(struct b2r2_memory_map, BLT_SSBA5)}, + {"BLT_SSBA6", offsetof(struct b2r2_memory_map, BLT_SSBA6)}, + {"BLT_SSBA7", offsetof(struct b2r2_memory_map, BLT_SSBA7)}, + {"BLT_SSBA8", offsetof(struct b2r2_memory_map, BLT_SSBA8)}, + {"BLT_STBA1", offsetof(struct b2r2_memory_map, BLT_STBA1)}, + {"BLT_STBA2", offsetof(struct b2r2_memory_map, BLT_STBA2)}, + {"BLT_STBA3", offsetof(struct b2r2_memory_map, BLT_STBA3)}, + {"BLT_STBA4", offsetof(struct b2r2_memory_map, BLT_STBA4)}, + {"BLT_CQ1_TRIG_IP", offsetof(struct b2r2_memory_map, BLT_CQ1_TRIG_IP)}, + {"BLT_CQ1_TRIG_CTL", offsetof(struct b2r2_memory_map, + BLT_CQ1_TRIG_CTL)}, + {"BLT_CQ1_PACE_CTL", offsetof(struct b2r2_memory_map, + BLT_CQ1_PACE_CTL)}, + {"BLT_CQ1_IP", offsetof(struct b2r2_memory_map, BLT_CQ1_IP)}, + {"BLT_CQ2_TRIG_IP", offsetof(struct b2r2_memory_map, BLT_CQ2_TRIG_IP)}, + {"BLT_CQ2_TRIG_CTL", offsetof(struct b2r2_memory_map, + BLT_CQ2_TRIG_CTL)}, + {"BLT_CQ2_PACE_CTL", offsetof(struct b2r2_memory_map, + BLT_CQ2_PACE_CTL)}, + {"BLT_CQ2_IP", offsetof(struct b2r2_memory_map, BLT_CQ2_IP)}, + {"BLT_AQ1_CTL", offsetof(struct b2r2_memory_map, BLT_AQ1_CTL)}, + {"BLT_AQ1_IP", offsetof(struct b2r2_memory_map, BLT_AQ1_IP)}, + {"BLT_AQ1_LNA", offsetof(struct b2r2_memory_map, BLT_AQ1_LNA)}, + {"BLT_AQ1_STA", offsetof(struct b2r2_memory_map, BLT_AQ1_STA)}, + {"BLT_AQ2_CTL", offsetof(struct b2r2_memory_map, BLT_AQ2_CTL)}, + {"BLT_AQ2_IP", offsetof(struct b2r2_memory_map, BLT_AQ2_IP)}, + {"BLT_AQ2_LNA", offsetof(struct b2r2_memory_map, BLT_AQ2_LNA)}, + {"BLT_AQ2_STA", offsetof(struct b2r2_memory_map, BLT_AQ2_STA)}, + {"BLT_AQ3_CTL", offsetof(struct b2r2_memory_map, BLT_AQ3_CTL)}, + {"BLT_AQ3_IP", offsetof(struct b2r2_memory_map, BLT_AQ3_IP)}, + {"BLT_AQ3_LNA", offsetof(struct b2r2_memory_map, BLT_AQ3_LNA)}, + {"BLT_AQ3_STA", offsetof(struct b2r2_memory_map, BLT_AQ3_STA)}, + {"BLT_AQ4_CTL", offsetof(struct b2r2_memory_map, BLT_AQ4_CTL)}, + {"BLT_AQ4_IP", offsetof(struct b2r2_memory_map, BLT_AQ4_IP)}, + {"BLT_AQ4_LNA", offsetof(struct b2r2_memory_map, BLT_AQ4_LNA)}, + {"BLT_AQ4_STA", offsetof(struct b2r2_memory_map, BLT_AQ4_STA)}, + {"BLT_SSBA9", offsetof(struct b2r2_memory_map, BLT_SSBA9)}, + {"BLT_SSBA10", offsetof(struct b2r2_memory_map, BLT_SSBA10)}, + {"BLT_SSBA11", offsetof(struct b2r2_memory_map, BLT_SSBA11)}, + {"BLT_SSBA12", offsetof(struct b2r2_memory_map, BLT_SSBA12)}, + {"BLT_SSBA13", offsetof(struct b2r2_memory_map, BLT_SSBA13)}, + {"BLT_SSBA14", offsetof(struct b2r2_memory_map, BLT_SSBA14)}, + {"BLT_SSBA15", offsetof(struct b2r2_memory_map, BLT_SSBA15)}, + {"BLT_SSBA16", offsetof(struct b2r2_memory_map, BLT_SSBA16)}, + {"BLT_SGA1", offsetof(struct b2r2_memory_map, BLT_SGA1)}, + {"BLT_SGA2", offsetof(struct b2r2_memory_map, BLT_SGA2)}, + {"BLT_ITM0", offsetof(struct b2r2_memory_map, BLT_ITM0)}, + {"BLT_ITM1", offsetof(struct b2r2_memory_map, BLT_ITM1)}, + {"BLT_ITM2", offsetof(struct b2r2_memory_map, BLT_ITM2)}, + {"BLT_ITM3", offsetof(struct b2r2_memory_map, BLT_ITM3)}, + {"BLT_DFV2", offsetof(struct b2r2_memory_map, BLT_DFV2)}, + {"BLT_DFV1", offsetof(struct b2r2_memory_map, BLT_DFV1)}, + {"BLT_PRI", offsetof(struct b2r2_memory_map, BLT_PRI)}, + {"PLUGS1_OP2", offsetof(struct b2r2_memory_map, PLUGS1_OP2)}, + {"PLUGS1_CHZ", offsetof(struct b2r2_memory_map, PLUGS1_CHZ)}, + {"PLUGS1_MSZ", offsetof(struct b2r2_memory_map, PLUGS1_MSZ)}, + {"PLUGS1_PGZ", offsetof(struct b2r2_memory_map, PLUGS1_PGZ)}, + {"PLUGS2_OP2", offsetof(struct b2r2_memory_map, PLUGS2_OP2)}, + {"PLUGS2_CHZ", offsetof(struct b2r2_memory_map, PLUGS2_CHZ)}, + {"PLUGS2_MSZ", offsetof(struct b2r2_memory_map, PLUGS2_MSZ)}, + {"PLUGS2_PGZ", offsetof(struct b2r2_memory_map, PLUGS2_PGZ)}, + {"PLUGS3_OP2", offsetof(struct b2r2_memory_map, PLUGS3_OP2)}, + {"PLUGS3_CHZ", offsetof(struct b2r2_memory_map, PLUGS3_CHZ)}, + {"PLUGS3_MSZ", offsetof(struct b2r2_memory_map, PLUGS3_MSZ)}, + {"PLUGS3_PGZ", offsetof(struct b2r2_memory_map, PLUGS3_PGZ)}, + {"PLUGT_OP2", offsetof(struct b2r2_memory_map, PLUGT_OP2)}, + {"PLUGT_CHZ", offsetof(struct b2r2_memory_map, PLUGT_CHZ)}, + {"PLUGT_MSZ", offsetof(struct b2r2_memory_map, PLUGT_MSZ)}, + {"PLUGT_PGZ", offsetof(struct b2r2_memory_map, PLUGT_PGZ)}, + {"BLT_NIP", offsetof(struct b2r2_memory_map, BLT_NIP)}, + {"BLT_CIC", offsetof(struct b2r2_memory_map, BLT_CIC)}, + {"BLT_INS", offsetof(struct b2r2_memory_map, BLT_INS)}, + {"BLT_ACK", offsetof(struct b2r2_memory_map, BLT_ACK)}, + {"BLT_TBA", offsetof(struct b2r2_memory_map, BLT_TBA)}, + {"BLT_TTY", offsetof(struct b2r2_memory_map, BLT_TTY)}, + {"BLT_TXY", offsetof(struct b2r2_memory_map, BLT_TXY)}, + {"BLT_TSZ", offsetof(struct b2r2_memory_map, BLT_TSZ)}, + {"BLT_S1CF", offsetof(struct b2r2_memory_map, BLT_S1CF)}, + {"BLT_S2CF", offsetof(struct b2r2_memory_map, BLT_S2CF)}, + {"BLT_S1BA", offsetof(struct b2r2_memory_map, BLT_S1BA)}, + {"BLT_S1TY", offsetof(struct b2r2_memory_map, BLT_S1TY)}, + {"BLT_S1XY", offsetof(struct b2r2_memory_map, BLT_S1XY)}, + {"BLT_S2BA", offsetof(struct b2r2_memory_map, BLT_S2BA)}, + {"BLT_S2TY", offsetof(struct b2r2_memory_map, BLT_S2TY)}, + {"BLT_S2XY", offsetof(struct b2r2_memory_map, BLT_S2XY)}, + {"BLT_S2SZ", offsetof(struct b2r2_memory_map, BLT_S2SZ)}, + {"BLT_S3BA", offsetof(struct b2r2_memory_map, BLT_S3BA)}, + {"BLT_S3TY", offsetof(struct b2r2_memory_map, BLT_S3TY)}, + {"BLT_S3XY", offsetof(struct b2r2_memory_map, BLT_S3XY)}, + {"BLT_S3SZ", offsetof(struct b2r2_memory_map, BLT_S3SZ)}, + {"BLT_CWO", offsetof(struct b2r2_memory_map, BLT_CWO)}, + {"BLT_CWS", offsetof(struct b2r2_memory_map, BLT_CWS)}, + {"BLT_CCO", offsetof(struct b2r2_memory_map, BLT_CCO)}, + {"BLT_CML", offsetof(struct b2r2_memory_map, BLT_CML)}, + {"BLT_FCTL", offsetof(struct b2r2_memory_map, BLT_FCTL)}, + {"BLT_PMK", offsetof(struct b2r2_memory_map, BLT_PMK)}, + {"BLT_RSF", offsetof(struct b2r2_memory_map, BLT_RSF)}, + {"BLT_RZI", offsetof(struct b2r2_memory_map, BLT_RZI)}, + {"BLT_HFP", offsetof(struct b2r2_memory_map, BLT_HFP)}, + {"BLT_VFP", offsetof(struct b2r2_memory_map, BLT_VFP)}, + {"BLT_Y_RSF", offsetof(struct b2r2_memory_map, BLT_Y_RSF)}, + {"BLT_Y_RZI", offsetof(struct b2r2_memory_map, BLT_Y_RZI)}, + {"BLT_Y_HFP", offsetof(struct b2r2_memory_map, BLT_Y_HFP)}, + {"BLT_Y_VFP", offsetof(struct b2r2_memory_map, BLT_Y_VFP)}, + {"BLT_KEY1", offsetof(struct b2r2_memory_map, BLT_KEY1)}, + {"BLT_KEY2", offsetof(struct b2r2_memory_map, BLT_KEY2)}, + {"BLT_SAR", offsetof(struct b2r2_memory_map, BLT_SAR)}, + {"BLT_USR", offsetof(struct b2r2_memory_map, BLT_USR)}, + {"BLT_IVMX0", offsetof(struct b2r2_memory_map, BLT_IVMX0)}, + {"BLT_IVMX1", offsetof(struct b2r2_memory_map, BLT_IVMX1)}, + {"BLT_IVMX2", offsetof(struct b2r2_memory_map, BLT_IVMX2)}, + {"BLT_IVMX3", offsetof(struct b2r2_memory_map, BLT_IVMX3)}, + {"BLT_OVMX0", offsetof(struct b2r2_memory_map, BLT_OVMX0)}, + {"BLT_OVMX1", offsetof(struct b2r2_memory_map, BLT_OVMX1)}, + {"BLT_OVMX2", offsetof(struct b2r2_memory_map, BLT_OVMX2)}, + {"BLT_OVMX3", offsetof(struct b2r2_memory_map, BLT_OVMX3)}, + {"BLT_VC1R", offsetof(struct b2r2_memory_map, BLT_VC1R)}, + {"BLT_Y_HFC0", offsetof(struct b2r2_memory_map, BLT_Y_HFC0)}, + {"BLT_Y_HFC1", offsetof(struct b2r2_memory_map, BLT_Y_HFC1)}, + {"BLT_Y_HFC2", offsetof(struct b2r2_memory_map, BLT_Y_HFC2)}, + {"BLT_Y_HFC3", offsetof(struct b2r2_memory_map, BLT_Y_HFC3)}, + {"BLT_Y_HFC4", offsetof(struct b2r2_memory_map, BLT_Y_HFC4)}, + {"BLT_Y_HFC5", offsetof(struct b2r2_memory_map, BLT_Y_HFC5)}, + {"BLT_Y_HFC6", offsetof(struct b2r2_memory_map, BLT_Y_HFC6)}, + {"BLT_Y_HFC7", offsetof(struct b2r2_memory_map, BLT_Y_HFC7)}, + {"BLT_Y_HFC8", offsetof(struct b2r2_memory_map, BLT_Y_HFC8)}, + {"BLT_Y_HFC9", offsetof(struct b2r2_memory_map, BLT_Y_HFC9)}, + {"BLT_Y_HFC10", offsetof(struct b2r2_memory_map, BLT_Y_HFC10)}, + {"BLT_Y_HFC11", offsetof(struct b2r2_memory_map, BLT_Y_HFC11)}, + {"BLT_Y_HFC12", offsetof(struct b2r2_memory_map, BLT_Y_HFC12)}, + {"BLT_Y_HFC13", offsetof(struct b2r2_memory_map, BLT_Y_HFC13)}, + {"BLT_Y_HFC14", offsetof(struct b2r2_memory_map, BLT_Y_HFC14)}, + {"BLT_Y_HFC15", offsetof(struct b2r2_memory_map, BLT_Y_HFC15)}, + {"BLT_Y_VFC0", offsetof(struct b2r2_memory_map, BLT_Y_VFC0)}, + {"BLT_Y_VFC1", offsetof(struct b2r2_memory_map, BLT_Y_VFC1)}, + {"BLT_Y_VFC2", offsetof(struct b2r2_memory_map, BLT_Y_VFC2)}, + {"BLT_Y_VFC3", offsetof(struct b2r2_memory_map, BLT_Y_VFC3)}, + {"BLT_Y_VFC4", offsetof(struct b2r2_memory_map, BLT_Y_VFC4)}, + {"BLT_Y_VFC5", offsetof(struct b2r2_memory_map, BLT_Y_VFC5)}, + {"BLT_Y_VFC6", offsetof(struct b2r2_memory_map, BLT_Y_VFC6)}, + {"BLT_Y_VFC7", offsetof(struct b2r2_memory_map, BLT_Y_VFC7)}, + {"BLT_Y_VFC8", offsetof(struct b2r2_memory_map, BLT_Y_VFC8)}, + {"BLT_Y_VFC9", offsetof(struct b2r2_memory_map, BLT_Y_VFC9)}, + {"BLT_HFC0", offsetof(struct b2r2_memory_map, BLT_HFC0)}, + {"BLT_HFC1", offsetof(struct b2r2_memory_map, BLT_HFC1)}, + {"BLT_HFC2", offsetof(struct b2r2_memory_map, BLT_HFC2)}, + {"BLT_HFC3", offsetof(struct b2r2_memory_map, BLT_HFC3)}, + {"BLT_HFC4", offsetof(struct b2r2_memory_map, BLT_HFC4)}, + {"BLT_HFC5", offsetof(struct b2r2_memory_map, BLT_HFC5)}, + {"BLT_HFC6", offsetof(struct b2r2_memory_map, BLT_HFC6)}, + {"BLT_HFC7", offsetof(struct b2r2_memory_map, BLT_HFC7)}, + {"BLT_HFC8", offsetof(struct b2r2_memory_map, BLT_HFC8)}, + {"BLT_HFC9", offsetof(struct b2r2_memory_map, BLT_HFC9)}, + {"BLT_HFC10", offsetof(struct b2r2_memory_map, BLT_HFC10)}, + {"BLT_HFC11", offsetof(struct b2r2_memory_map, BLT_HFC11)}, + {"BLT_HFC12", offsetof(struct b2r2_memory_map, BLT_HFC12)}, + {"BLT_HFC13", offsetof(struct b2r2_memory_map, BLT_HFC13)}, + {"BLT_HFC14", offsetof(struct b2r2_memory_map, BLT_HFC14)}, + {"BLT_HFC15", offsetof(struct b2r2_memory_map, BLT_HFC15)}, + {"BLT_VFC0", offsetof(struct b2r2_memory_map, BLT_VFC0)}, + {"BLT_VFC1", offsetof(struct b2r2_memory_map, BLT_VFC1)}, + {"BLT_VFC2", offsetof(struct b2r2_memory_map, BLT_VFC2)}, + {"BLT_VFC3", offsetof(struct b2r2_memory_map, BLT_VFC3)}, + {"BLT_VFC4", offsetof(struct b2r2_memory_map, BLT_VFC4)}, + {"BLT_VFC5", offsetof(struct b2r2_memory_map, BLT_VFC5)}, + {"BLT_VFC6", offsetof(struct b2r2_memory_map, BLT_VFC6)}, + {"BLT_VFC7", offsetof(struct b2r2_memory_map, BLT_VFC7)}, + {"BLT_VFC8", offsetof(struct b2r2_memory_map, BLT_VFC8)}, + {"BLT_VFC9", offsetof(struct b2r2_memory_map, BLT_VFC9)}, +}; + +#ifdef HANDLE_TIMEOUTED_JOBS +/** + * printk_regs() - Print B2R2 registers to printk + */ +static void printk_regs(struct b2r2_core *core) +{ +#ifdef CONFIG_B2R2_DEBUG + int i; + + for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) { + unsigned long value = readl( + (unsigned long *) (((u8 *) core->hw) + + debugfs_regs[i].offset)); + b2r2_log_regdump(core->dev, "%s: %08lX\n", + debugfs_regs[i].name, + value); + } +#endif +} +#endif + +/** + * debugfs_b2r2_reg_read() - Implements debugfs read for B2R2 register + * + * @filp: File pointer + * @buf: User space buffer + * @count: Number of bytes to read + * @f_pos: File position + * + * Returns number of bytes read or negative error code + */ +static int debugfs_b2r2_reg_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + size_t dev_size; + int ret = 0; + unsigned long value; + char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL); + + if (Buf == NULL) { + ret = -ENOMEM; + goto out; + } + + /* Read from B2R2 */ + value = readl((unsigned long *) + filp->f_dentry->d_inode->i_private); + + /* Build the string */ + dev_size = sprintf(Buf, "%8lX\n", value); + + /* No more to read if offset != 0 */ + if (*f_pos > dev_size) + goto out; + + if (*f_pos + count > dev_size) + count = dev_size - *f_pos; + + /* Return it to user space */ + if (copy_to_user(buf, Buf, count)) + ret = -EINVAL; + *f_pos += count; + ret = count; + +out: + if (Buf != NULL) + kfree(Buf); + return ret; +} + +/** + * debugfs_b2r2_reg_write() - Implements debugfs write for B2R2 register + * + * @filp: File pointer + * @buf: User space buffer + * @count: Number of bytes to write + * @f_pos: File position + * + * Returns number of bytes written or negative error code + */ +static int debugfs_b2r2_reg_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + char Buf[80]; + u32 reg_value; + int ret = 0; + + /* Adjust count */ + if (count >= sizeof(Buf)) + count = sizeof(Buf) - 1; + /* Get it from user space */ + if (copy_from_user(Buf, buf, count)) + return -EINVAL; + Buf[count] = 0; + /* Convert from hex string */ + if (sscanf(Buf, "%8lX", (unsigned long *) ®_value) != 1) + return -EINVAL; + + writel(reg_value, (u32 *) + filp->f_dentry->d_inode->i_private); + + *f_pos += count; + ret = count; + + return ret; +} + +/** + * debugfs_b2r2_reg_fops() - File operations for B2R2 register debugfs + */ +static const struct file_operations debugfs_b2r2_reg_fops = { + .owner = THIS_MODULE, + .read = debugfs_b2r2_reg_read, + .write = debugfs_b2r2_reg_write, +}; + +/** + * debugfs_b2r2_regs_read() - Implements debugfs read for B2R2 register dump + * + * @filp: File pointer + * @buf: User space buffer + * @count: Number of bytes to read + * @f_pos: File position + * + * Returns number of bytes written or negative error code + */ +static int debugfs_b2r2_regs_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + size_t dev_size = 0; + int ret = 0; + int i; + char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL); + + if (Buf == NULL) { + ret = -ENOMEM; + goto out; + } + + /* Build a giant string containing all registers */ + for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) { + unsigned long value = + readl((u32 *) (((u8 *) + filp->f_dentry->d_inode->i_private) + + debugfs_regs[i].offset)); + dev_size += sprintf(Buf + dev_size, "%s: %08lX\n", + debugfs_regs[i].name, + value); + } + + /* No more to read if offset != 0 */ + if (*f_pos > dev_size) + goto out; + + if (*f_pos + count > dev_size) + count = dev_size - *f_pos; + + if (copy_to_user(buf, Buf, count)) + ret = -EINVAL; + *f_pos += count; + ret = count; + +out: + if (Buf != NULL) + kfree(Buf); + return ret; +} + +/** + * debugfs_b2r2_regs_fops() - File operations for B2R2 register dump debugfs + */ +static const struct file_operations debugfs_b2r2_regs_fops = { + .owner = THIS_MODULE, + .read = debugfs_b2r2_regs_read, +}; + +/** + * debugfs_b2r2_stat_read() - Implements debugfs read for B2R2 statistics + * + * @filp: File pointer + * @buf: User space buffer + * @count: Number of bytes to read + * @f_pos: File position + * + * Returns number of bytes read or negative error code + */ +static int debugfs_b2r2_stat_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + size_t dev_size = 0; + int ret = 0; + int i = 0; + char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL); + struct b2r2_core *core = filp->f_dentry->d_inode->i_private; + + if (Buf == NULL) { + ret = -ENOMEM; + goto out; + } + + /* Build a string containing all statistics */ + dev_size += sprintf(Buf + dev_size, "Interrupts : %lu\n", + core->stat_n_irq); + dev_size += sprintf(Buf + dev_size, "Added jobs : %lu\n", + core->stat_n_jobs_added); + dev_size += sprintf(Buf + dev_size, "Removed jobs : %lu\n", + core->stat_n_jobs_removed); + dev_size += sprintf(Buf + dev_size, "Jobs in prio list : %lu\n", + core->stat_n_jobs_in_prio_list); + dev_size += sprintf(Buf + dev_size, "Active jobs : %lu\n", + core->n_active_jobs); + for (i = 0; i < ARRAY_SIZE(core->active_jobs); i++) + dev_size += sprintf(Buf + dev_size, + " Job in queue %d : 0x%08lx\n", + i, (unsigned long) core->active_jobs[i]); + dev_size += sprintf(Buf + dev_size, "Clock requests : %lu\n", + core->clock_request_count); + + /* No more to read if offset != 0 */ + if (*f_pos > dev_size) + goto out; + + if (*f_pos + count > dev_size) + count = dev_size - *f_pos; + + if (copy_to_user(buf, Buf, count)) + ret = -EINVAL; + *f_pos += count; + ret = count; + +out: + if (Buf != NULL) + kfree(Buf); + return ret; +} + +/** + * debugfs_b2r2_stat_fops() - File operations for B2R2 statistics debugfs + */ +static const struct file_operations debugfs_b2r2_stat_fops = { + .owner = THIS_MODULE, + .read = debugfs_b2r2_stat_read, +}; + + +/** + * debugfs_b2r2_clock_read() - Implements debugfs read for + * PMU B2R2 clock register + * @filp: File pointer + * @buf: User space buffer + * @count: Number of bytes to read + * @f_pos: File position + * + * Returns number of bytes read or negative error code + */ +static int debugfs_b2r2_clock_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + /* 10 characters hex number + newline + string terminator; */ + char Buf[10+2]; + size_t dev_size; + int ret = 0; + struct b2r2_core *core = filp->f_dentry->d_inode->i_private; + + unsigned long value = clk_get_rate(core->b2r2_clock); + + dev_size = sprintf(Buf, "%#010lx\n", value); + + /* No more to read if offset != 0 */ + if (*f_pos > dev_size) + goto out; + + if (*f_pos + count > dev_size) + count = dev_size - *f_pos; + + if (copy_to_user(buf, Buf, count)) + ret = -EINVAL; + *f_pos += count; + ret = count; + +out: + return ret; +} + +/** + * debugfs_b2r2_clock_write() - Implements debugfs write for + * PMU B2R2 clock register + * @filp: File pointer + * @buf: User space buffer + * @count: Number of bytes to write + * @f_pos: File position + * + * Returns number of bytes written or negative error code + */ +static int debugfs_b2r2_clock_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + char Buf[80]; + u32 reg_value; + int ret = 0; + + if (count >= sizeof(Buf)) + count = sizeof(Buf) - 1; + if (copy_from_user(Buf, buf, count)) + return -EINVAL; + Buf[count] = 0; + if (sscanf(Buf, "%8lX", (unsigned long *) ®_value) != 1) + return -EINVAL; + + /*not working yet*/ + /*clk_set_rate(b2r2_core.b2r2_clock, (unsigned long) reg_value);*/ + + *f_pos += count; + ret = count; + + return ret; +} + +/** + * debugfs_b2r2_clock_fops() - File operations for PMU B2R2 clock debugfs + */ +static const struct file_operations debugfs_b2r2_clock_fops = { + .owner = THIS_MODULE, + .read = debugfs_b2r2_clock_read, + .write = debugfs_b2r2_clock_write, +}; + +#endif + +/** + * + * init_hw() - B2R2 Hardware reset & initiliaze + * + * @pdev: B2R2 platform device + * + * 1)Register interrupt handler + * + * 2)B2R2 Register map + * + * 3)For resetting B2R2 hardware,write to B2R2 Control register the + * B2R2BLT_CTLGLOBAL_soft_reset and then polling for on + * B2R2 status register for B2R2BLT_STA1BDISP_IDLE flag. + * + * 4)Wait for B2R2 hardware to be idle (on a timeout rather than while loop) + * + * 5)Driver status reset + * + * 6)Recover from any error without any leaks. + * + */ +static int init_hw(struct b2r2_core *core) +{ + int result = 0; + u32 uTimeOut = B2R2_DRIVER_TIMEOUT_VALUE; + + /* Put B2R2 into reset */ + clear_interrupts(core); + + writel(readl(&core->hw->BLT_CTL) | B2R2BLT_CTLGLOBAL_soft_reset, + &core->hw->BLT_CTL); + + /* Set up interrupt handler */ + result = request_irq(core->irq, b2r2_irq_handler, 0, + "b2r2-interrupt", core); + if (result) { + b2r2_log_err(core->dev, + "%s: failed to register IRQ for B2R2\n", __func__); + goto b2r2_init_request_irq_failed; + } + + b2r2_log_info(core->dev, "do a global reset..\n"); + + /* Release reset */ + writel(0x00000000, &core->hw->BLT_CTL); + + b2r2_log_info(core->dev, "wait for B2R2 to be idle..\n"); + + /** Wait for B2R2 to be idle (on a timeout rather than while loop) */ + while ((uTimeOut > 0) && + ((readl(&core->hw->BLT_STA1) & + B2R2BLT_STA1BDISP_IDLE) == 0x0)) + uTimeOut--; + if (uTimeOut == 0) { + b2r2_log_err(core->dev, + "%s: B2R2 not idle after SW reset\n", __func__); + result = -EAGAIN; + goto b2r2_core_init_hw_timeout; + } + +#ifdef CONFIG_DEBUG_FS + /* Register debug fs files for register access */ + if (core->debugfs_core_root_dir && !core->debugfs_regs_dir) { + int i; + core->debugfs_regs_dir = debugfs_create_dir("regs", + core->debugfs_core_root_dir); + debugfs_create_file("all", 0666, core->debugfs_regs_dir, + (void *)core->hw, &debugfs_b2r2_regs_fops); + /* Create debugfs entries for all static registers */ + for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) + debugfs_create_file(debugfs_regs[i].name, 0666, + core->debugfs_regs_dir, + (void *)(((u8 *) core->hw) + + debugfs_regs[i].offset), + &debugfs_b2r2_reg_fops); + } +#endif + + b2r2_log_info(core->dev, "%s ended..\n", __func__); + return result; + +/** Recover from any error without any leaks */ +b2r2_core_init_hw_timeout: + /** Free B2R2 interrupt handler */ + free_irq(core->irq, core); + +b2r2_init_request_irq_failed: + if (core->hw) + iounmap(core->hw); + core->hw = NULL; + + return result; +} + + +/** + * exit_hw() - B2R2 Hardware exit + * + * core->lock _must_ NOT be held + */ +static void exit_hw(struct b2r2_core *core) +{ + unsigned long flags; + + b2r2_log_info(core->dev, "%s started..\n", __func__); + +#ifdef CONFIG_DEBUG_FS + /* Unregister our debugfs entries */ + if (core->debugfs_regs_dir) { + debugfs_remove_recursive(core->debugfs_regs_dir); + core->debugfs_regs_dir = NULL; + } +#endif + b2r2_log_debug(core->dev, "%s: locking core->lock\n", __func__); + spin_lock_irqsave(&core->lock, flags); + + /* Cancel all pending jobs */ + b2r2_log_debug(core->dev, "%s: canceling pending jobs\n", __func__); + exit_job_list(core, &core->prio_queue); + + /* Soft reset B2R2 (Close all DMA, + reset all state to idle, reset regs)*/ + b2r2_log_debug(core->dev, "%s: putting b2r2 in reset\n", __func__); + writel(readl(&core->hw->BLT_CTL) | B2R2BLT_CTLGLOBAL_soft_reset, + &core->hw->BLT_CTL); + + b2r2_log_debug(core->dev, "%s: clearing interrupts\n", __func__); + clear_interrupts(core); + + /** Free B2R2 interrupt handler */ + b2r2_log_debug(core->dev, "%s: freeing interrupt handler\n", __func__); + free_irq(core->irq, core); + + b2r2_log_debug(core->dev, "%s: unlocking core->lock\n", __func__); + spin_unlock_irqrestore(&core->lock, flags); + + b2r2_log_info(core->dev, "%s ended...\n", __func__); +} + +/** + * b2r2_probe() - This routine loads the B2R2 core driver + * + * @pdev: platform device. + */ +static int b2r2_probe(struct platform_device *pdev) +{ + int ret = 0; + struct resource *res; + struct b2r2_core *core; + struct b2r2_control *control; + + BUG_ON(pdev == NULL); + BUG_ON(pdev->id < 0 || pdev->id >= B2R2_MAX_NBR_DEVICES); + + core = kzalloc(sizeof(*core), GFP_KERNEL); + if (!core) { + dev_err(&pdev->dev, "b2r2 core alloc failed\n"); + ret = -EINVAL; + goto b2r2_probe_core_alloc_fail; + } + + core->dev = &pdev->dev; + dev_set_drvdata(core->dev, core); + if (pdev->id) + snprintf(core->name, sizeof(core->name), "b2r2_%d", pdev->id); + else + snprintf(core->name, sizeof(core->name), "b2r2"); + + dev_info(&pdev->dev, "init started.\n"); + + /* Init spin locks */ + spin_lock_init(&core->lock); + + /* Init job queues */ + INIT_LIST_HEAD(&core->prio_queue); + +#ifdef HANDLE_TIMEOUTED_JOBS + /* Create work queue for callbacks & timeout */ + INIT_DELAYED_WORK(&core->timeout_work, timeout_work_function); +#endif + + /* Work queue for callbacks and timeout management */ + core->work_queue = create_workqueue("B2R2"); + if (!core->work_queue) { + ret = -ENOMEM; + goto b2r2_probe_no_work_queue; + } + + /* Get the clock for B2R2 */ + core->b2r2_clock = clk_get(core->dev, "b2r2"); + if (IS_ERR(core->b2r2_clock)) { + ret = PTR_ERR(core->b2r2_clock); + dev_err(&pdev->dev, "clk_get b2r2 failed\n"); + goto b2r2_probe_no_clk; + } + + /* Get the B2R2 regulator */ + core->b2r2_reg = regulator_get(core->dev, "vsupply"); + if (IS_ERR(core->b2r2_reg)) { + ret = PTR_ERR(core->b2r2_reg); + dev_err(&pdev->dev, "regulator_get vsupply failed " + "(dev_name=%s)\n", dev_name(core->dev)); + goto b2r2_probe_no_reg; + } + + /* Init power management */ + mutex_init(&core->domain_lock); + INIT_DELAYED_WORK_DEFERRABLE(&core->domain_disable_work, + domain_disable_work_function); + core->domain_enabled = false; + + /* Map B2R2 into kernel virtual memory space */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + goto b2r2_probe_no_res; + + /* Hook up irq */ + core->irq = platform_get_irq(pdev, 0); + if (core->irq <= 0) { + dev_err(&pdev->dev, "%s: Failed to request irq (irq=%d)\n", + __func__, core->irq); + goto b2r2_failed_irq_get; + } + + core->hw = (struct b2r2_memory_map *) ioremap(res->start, + res->end - res->start + 1); + if (core->hw == NULL) { + dev_err(&pdev->dev, "%s: ioremap failed\n", __func__); + ret = -ENOMEM; + goto b2r2_probe_ioremap_failed; + } + + dev_dbg(core->dev, "b2r2 structure address %p\n", core->hw); + + control = kzalloc(sizeof(*control), GFP_KERNEL); + if (!control) { + dev_err(&pdev->dev, "b2r2 control alloc failed\n"); + ret = -EINVAL; + goto b2r2_probe_control_alloc_fail; + } + + control->miscdev.parent = core->dev; + control->data = (void *)core; + control->id = pdev->id; + control->dev = &pdev->dev; /* Temporary device */ + snprintf(control->name, sizeof(control->name), "%s_blt", core->name); + + core->op_size = B2R2_PLUG_OPCODE_SIZE_DEFAULT; + core->ch_size = B2R2_PLUG_CHUNK_SIZE_DEFAULT; + core->pg_size = B2R2_PLUG_PAGE_SIZE_DEFAULT; + core->mg_size = B2R2_PLUG_MESSAGE_SIZE_DEFAULT; + core->min_req_time = 0; + +#ifdef CONFIG_DEBUG_FS + core->debugfs_root_dir = debugfs_create_dir(core->name, NULL); + core->debugfs_core_root_dir = debugfs_create_dir("core", + core->debugfs_root_dir); + debugfs_create_file("stats", 0666, core->debugfs_core_root_dir, + core, &debugfs_b2r2_stat_fops); + debugfs_create_file("clock", 0666, core->debugfs_core_root_dir, + core, &debugfs_b2r2_clock_fops); + debugfs_create_u8("op_size", 0666, core->debugfs_core_root_dir, + &core->op_size); + debugfs_create_u8("ch_size", 0666, core->debugfs_core_root_dir, + &core->ch_size); + debugfs_create_u8("pg_size", 0666, core->debugfs_core_root_dir, + &core->pg_size); + debugfs_create_u8("mg_size", 0666, core->debugfs_core_root_dir, + &core->mg_size); + debugfs_create_u16("min_req_time", 0666, core->debugfs_core_root_dir, + &core->min_req_time); + + control->debugfs_debug_root_dir = debugfs_create_dir("debug", + core->debugfs_root_dir); + control->mem_heap.debugfs_root_dir = debugfs_create_dir("mem", + core->debugfs_root_dir); + control->debugfs_root_dir = debugfs_create_dir("blt", + core->debugfs_root_dir); +#endif + + ret = b2r2_debug_init(control); + if (ret < 0) { + dev_err(&pdev->dev, "b2r2_debug_init failed\n"); + goto b2r2_probe_debug_init_failed; + } + + /* Initialize b2r2_blt module. FIXME: Module of it's own + or perhaps a dedicated module init c file? */ + ret = b2r2_blt_module_init(control); + if (ret < 0) { + b2r2_log_err(&pdev->dev, "b2r2_blt_module_init failed\n"); + goto b2r2_probe_blt_init_fail; + } + + core->control = control; + b2r2_core[pdev->id] = core; + dev_info(&pdev->dev, "init done.\n"); + + return ret; + +/** Recover from any error if something fails */ +b2r2_probe_blt_init_fail: + kfree(control); +b2r2_probe_control_alloc_fail: +b2r2_probe_ioremap_failed: +b2r2_failed_irq_get: +b2r2_probe_no_res: + regulator_put(core->b2r2_reg); +b2r2_probe_no_reg: + clk_put(core->b2r2_clock); +b2r2_probe_no_clk: + destroy_workqueue(core->work_queue); + core->work_queue = NULL; +b2r2_probe_no_work_queue: + b2r2_debug_exit(); +b2r2_probe_debug_init_failed: +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(core->debugfs_root_dir); +#endif + kfree(core); +b2r2_probe_core_alloc_fail: + dev_info(&pdev->dev, "init done with errors.\n"); + + return ret; +} + + + +/** + * b2r2_remove - This routine unloads b2r2 driver + * + * @pdev: platform device. + */ +static int b2r2_remove(struct platform_device *pdev) +{ + unsigned long flags; + struct b2r2_core *core; + + BUG_ON(pdev == NULL); + + core = dev_get_drvdata(&pdev->dev); + BUG_ON(core == NULL); + b2r2_log_info(&pdev->dev, "%s: Started\n", __func__); + +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(core->debugfs_root_dir); +#endif + + /* Flush B2R2 work queue (call all callbacks) */ + flush_workqueue(core->work_queue); + + /* Exit b2r2 blt module */ + b2r2_blt_module_exit(core->control); + + kfree(core->control); + +#ifdef HANDLE_TIMEOUTED_JOBS + cancel_delayed_work(&core->timeout_work); +#endif + + /* Flush B2R2 work queue (call all callbacks for + cancelled jobs) */ + flush_workqueue(core->work_queue); + + /* Make sure the power is turned off */ + cancel_delayed_work_sync(&core->domain_disable_work); + + /** Unmap B2R2 registers */ + b2r2_log_info(&pdev->dev, "unmap b2r2 registers..\n"); + if (core->hw) { + iounmap(core->hw); + core->hw = NULL; + } + + destroy_workqueue(core->work_queue); + + spin_lock_irqsave(&core->lock, flags); + core->work_queue = NULL; + spin_unlock_irqrestore(&core->lock, flags); + + /* Return the clock */ + clk_put(core->b2r2_clock); + regulator_put(core->b2r2_reg); + + core->dev = NULL; + kfree(core); + b2r2_core[pdev->id] = NULL; + + b2r2_debug_exit(); + + b2r2_log_info(&pdev->dev, "%s: Ended\n", __func__); + + return 0; +} +/** + * b2r2_suspend() - This routine puts the B2R2 device in to sustend state. + * @pdev: platform device. + * + * This routine stores the current state of the b2r2 device and puts in to + * suspend state. + * + */ +int b2r2_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct b2r2_core *core; + + BUG_ON(pdev == NULL); + core = dev_get_drvdata(&pdev->dev); + BUG_ON(core == NULL); + b2r2_log_info(core->dev, "%s\n", __func__); + + /* Flush B2R2 work queue (call all callbacks) */ + flush_workqueue(core->work_queue); + +#ifdef HANDLE_TIMEOUTED_JOBS + cancel_delayed_work(&core->timeout_work); +#endif + + /* Flush B2R2 work queue (call all callbacks for + cancelled jobs) */ + flush_workqueue(core->work_queue); + + /* Make sure power is turned off */ + cancel_delayed_work_sync(&core->domain_disable_work); + + return 0; +} + + +/** + * b2r2_resume() - This routine resumes the B2R2 device from sustend state. + * @pdev: platform device. + * + * This routine restore back the current state of the b2r2 device resumes. + * + */ +int b2r2_resume(struct platform_device *pdev) +{ + struct b2r2_core *core; + + BUG_ON(pdev == NULL); + core = dev_get_drvdata(&pdev->dev); + BUG_ON(core == NULL); + b2r2_log_info(core->dev, "%s\n", __func__); + + return 0; +} + +/** + * struct platform_b2r2_driver - Platform driver configuration for the + * B2R2 core driver + */ +static struct platform_driver platform_b2r2_driver = { + .remove = b2r2_remove, + .driver = { + .name = "b2r2", + }, + /** TODO implement power mgmt functions */ + .suspend = b2r2_suspend, + .resume = b2r2_resume, +}; + + +/** + * b2r2_init() - Module init function for the B2R2 core module + */ +static int __init b2r2_init(void) +{ + printk(KERN_INFO "%s\n", __func__); + return platform_driver_probe(&platform_b2r2_driver, b2r2_probe); +} +module_init(b2r2_init); + +/** + * b2r2_exit() - Module exit function for the B2R2 core module + */ +static void __exit b2r2_exit(void) +{ + printk(KERN_INFO "%s\n", __func__); + platform_driver_unregister(&platform_b2r2_driver); + return; +} +module_exit(b2r2_exit); + + +/** Module is having GPL license */ + +MODULE_LICENSE("GPL"); + +/** Module author & discription */ + +MODULE_AUTHOR("Robert Fekete (robert.fekete@stericsson.com)"); +MODULE_DESCRIPTION("B2R2 Core driver"); diff --git a/drivers/video/b2r2/b2r2_core.h b/drivers/video/b2r2/b2r2_core.h new file mode 100644 index 00000000000..991dd9d9d1b --- /dev/null +++ b/drivers/video/b2r2/b2r2_core.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 core driver + * + * Author: Robert Fekete <robert.fekete@stericsson.com> + * Author: Paul Wannback + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __B2R2_CORE_H__ +#define __B2R2_CORE_H__ + +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/wait.h> +#include <linux/workqueue.h> + + +/** + * b2r2_core_job_add() - Adds a job to B2R2 job queues + * + * The job reference count will be increased after this function + * has been called and b2r2_core_job_release() must be called to + * release the reference. The job callback function will be always + * be called after the job is done or cancelled. + * + * @control: The b2r2 control entity + * @job: Job to be added + * + * Returns 0 if OK else negative error code + * + */ +int b2r2_core_job_add(struct b2r2_control *control, + struct b2r2_core_job *job); + +/** + * b2r2_core_job_wait() - Waits for an added job to be done. + * + * @job: Job to wait for + * + * Returns 0 if job done else negative error code + * + */ +int b2r2_core_job_wait(struct b2r2_core_job *job); + +/** + * b2r2_core_job_cancel() - Cancel an already added job. + * + * @job: Job to cancel + * + * Returns 0 if job cancelled or done else negative error code + * + */ +int b2r2_core_job_cancel(struct b2r2_core_job *job); + +/** + * b2r2_core_job_find() - Finds job with given job id + * + * Reference count will be increased for the found job + * + * @control: The b2r2 control entity + * @job_id: Job id to find + * + * Returns job if found, else NULL + * + */ +struct b2r2_core_job *b2r2_core_job_find(struct b2r2_control *control, + int job_id); + +/** + * b2r2_core_job_find_first_with_tag() - Finds first job with given tag + * + * Reference count will be increased for the found job. + * This function can be used to find all jobs for a client, i.e. + * when cancelling all jobs for a client. + * + * @control: The b2r2 control entity + * @tag: Tag to find + * + * Returns job if found, else NULL + * + */ +struct b2r2_core_job *b2r2_core_job_find_first_with_tag( + struct b2r2_control *control, int tag); + +/** + * b2r2_core_job_addref() - Increase the job reference count. + * + * @job: Job to increase reference count for. + * @caller: The function calling this function (for debug) + */ +void b2r2_core_job_addref(struct b2r2_core_job *job, const char *caller); + +/** + * b2r2_core_job_release() - Decrease the job reference count. The + * job will be released (the release() function + * will be called) when the reference count + * reaches zero. + * + * @job: Job to decrease reference count for. + * @caller: The function calling this function (for debug) + */ +void b2r2_core_job_release(struct b2r2_core_job *job, const char *caller); + +#endif /* !defined(__B2R2_CORE_JOB_H__) */ diff --git a/drivers/video/b2r2/b2r2_debug.c b/drivers/video/b2r2/b2r2_debug.c new file mode 100644 index 00000000000..23a0b1aa9ac --- /dev/null +++ b/drivers/video/b2r2/b2r2_debug.c @@ -0,0 +1,338 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 dynamic debug + * + * Author: Fredrik Allansson <fredrik.allansson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include "b2r2_debug.h" +#include <linux/debugfs.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/uaccess.h> + +int b2r2_log_levels[B2R2_LOG_LEVEL_COUNT]; +static struct dentry *log_lvl_dir; +static int module_init; + +#define CHARS_IN_NODE_DUMP 1544 +#define DUMPED_NODE_SIZE (CHARS_IN_NODE_DUMP * sizeof(char) + 1) + +static void dump_node(char *dst, struct b2r2_node *node) +{ + dst += sprintf(dst, "node 0x%08x ------------------\n", + (unsigned int)node); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_NIP:", node->node.GROUP0.B2R2_NIP); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_CIC:", node->node.GROUP0.B2R2_CIC); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_INS:", node->node.GROUP0.B2R2_INS); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_ACK:", node->node.GROUP0.B2R2_ACK); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_TBA:", node->node.GROUP1.B2R2_TBA); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_TTY:", node->node.GROUP1.B2R2_TTY); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_TXY:", node->node.GROUP1.B2R2_TXY); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_TSZ:", node->node.GROUP1.B2R2_TSZ); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_S1CF:", node->node.GROUP2.B2R2_S1CF); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_S2CF:", node->node.GROUP2.B2R2_S2CF); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_S1BA:", node->node.GROUP3.B2R2_SBA); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_S1TY:", node->node.GROUP3.B2R2_STY); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_S1XY:", node->node.GROUP3.B2R2_SXY); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_S1SZ:", node->node.GROUP3.B2R2_SSZ); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_S2BA:", node->node.GROUP4.B2R2_SBA); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_S2TY:", node->node.GROUP4.B2R2_STY); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_S2XY:", node->node.GROUP4.B2R2_SXY); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_S2SZ:", node->node.GROUP4.B2R2_SSZ); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_S3BA:", node->node.GROUP5.B2R2_SBA); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_S3TY:", node->node.GROUP5.B2R2_STY); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_S3XY:", node->node.GROUP5.B2R2_SXY); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_S3SZ:", node->node.GROUP5.B2R2_SSZ); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_CWO:", node->node.GROUP6.B2R2_CWO); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_CWS:", node->node.GROUP6.B2R2_CWS); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_CCO:", node->node.GROUP7.B2R2_CCO); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_CML:", node->node.GROUP7.B2R2_CML); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_PMK:", node->node.GROUP8.B2R2_PMK); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_FCTL:", node->node.GROUP8.B2R2_FCTL); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_RSF:", node->node.GROUP9.B2R2_RSF); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_RZI:", node->node.GROUP9.B2R2_RZI); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_HFP:", node->node.GROUP9.B2R2_HFP); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_VFP:", node->node.GROUP9.B2R2_VFP); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_Y_RSF:", node->node.GROUP10.B2R2_RSF); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_Y_RZI:", node->node.GROUP10.B2R2_RZI); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_Y_HFP:", node->node.GROUP10.B2R2_HFP); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_Y_VFP:", node->node.GROUP10.B2R2_VFP); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_FF0:", node->node.GROUP11.B2R2_FF0); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_FF1:", node->node.GROUP11.B2R2_FF1); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_FF2:", node->node.GROUP11.B2R2_FF2); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_FF3:", node->node.GROUP11.B2R2_FF3); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_KEY1:", node->node.GROUP12.B2R2_KEY1); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_KEY2:", node->node.GROUP12.B2R2_KEY2); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_XYL:", node->node.GROUP13.B2R2_XYL); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_XYP:", node->node.GROUP13.B2R2_XYP); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_SAR:", node->node.GROUP14.B2R2_SAR); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_USR:", node->node.GROUP14.B2R2_USR); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_IVMX0:", node->node.GROUP15.B2R2_VMX0); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_IVMX1:", node->node.GROUP15.B2R2_VMX1); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_IVMX2:", node->node.GROUP15.B2R2_VMX2); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_IVMX3:", node->node.GROUP15.B2R2_VMX3); + dst += sprintf(dst, "--\n"); + + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_OVMX0:", node->node.GROUP16.B2R2_VMX0); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_OVMX1:", node->node.GROUP16.B2R2_VMX1); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_OVMX2:", node->node.GROUP16.B2R2_VMX2); + dst += sprintf(dst, "%s\t0x%08x\n", + "B2R2_OVMX3:", node->node.GROUP16.B2R2_VMX3); + dst += sprintf(dst, "--\n"); + +} + +void b2r2_debug_job_done(struct b2r2_control *cont, + struct b2r2_node *first_node) +{ + struct b2r2_node *node = first_node; + struct b2r2_node **dst_node; + unsigned int node_count = 0; + + while (node != NULL) { + node_count++; + node = node->next; + } + + mutex_lock(&cont->last_job_lock); + + if (cont->last_job) { + node = cont->last_job; + while (node != NULL) { + struct b2r2_node *tmp = node->next; + kfree(node); + node = tmp; + } + cont->last_job = NULL; + } + + node = first_node; + dst_node = &cont->last_job; + while (node != NULL) { + *dst_node = kzalloc(sizeof(**dst_node), GFP_KERNEL); + if (!(*dst_node)) + goto last_job_alloc_failed; + + memcpy(*dst_node, node, sizeof(**dst_node)); + + dst_node = &((*dst_node)->next); + node = node->next; + } + + mutex_unlock(&cont->last_job_lock); + + return; + +last_job_alloc_failed: + mutex_unlock(&cont->last_job_lock); + + while (cont->last_job != NULL) { + struct b2r2_node *tmp = cont->last_job->next; + kfree(cont->last_job); + cont->last_job = tmp; + } + + return; +} + +static ssize_t last_job_read(struct file *filp, char __user *buf, + size_t bytes, loff_t *off) +{ + struct b2r2_control *cont = filp->f_dentry->d_inode->i_private; + struct b2r2_node *node = cont->last_job; + int node_count = 0; + int i; + + size_t size; + size_t count; + loff_t offs = *off; + + for (; node != NULL; node = node->next) + node_count++; + + size = node_count * DUMPED_NODE_SIZE; + + if (node_count != cont->prev_node_count) { + kfree(cont->last_job_chars); + + cont->last_job_chars = kzalloc(size, GFP_KERNEL); + if (!cont->last_job_chars) + return 0; + cont->prev_node_count = node_count; + } + + mutex_lock(&cont->last_job_lock); + node = cont->last_job; + for (i = 0; i < node_count; i++) { + BUG_ON(node == NULL); + dump_node(cont->last_job_chars + + i * DUMPED_NODE_SIZE/sizeof(char), + node); + node = node->next; + } + mutex_unlock(&cont->last_job_lock); + + if (offs > size) + return 0; + + if (offs + bytes > size) + count = size - offs; + else + count = bytes; + + if (copy_to_user(buf, cont->last_job_chars + offs, count)) + return -EFAULT; + + *off = offs + count; + return count; +} + +static const struct file_operations last_job_fops = { + .read = last_job_read, +}; + +int b2r2_debug_init(struct b2r2_control *cont) +{ + int i; + + if (!module_init) { + for (i = 0; i < B2R2_LOG_LEVEL_COUNT; i++) + b2r2_log_levels[i] = 0; + +#if !defined(CONFIG_DYNAMIC_DEBUG) && defined(CONFIG_DEBUG_FS) + /* + * If dynamic debug is disabled we need some other way to + * control the log prints + */ + log_lvl_dir = debugfs_create_dir("b2r2_log", NULL); + + /* No need to save the files, + * they will be removed recursively */ + (void)debugfs_create_bool("warnings", 0644, log_lvl_dir, + &b2r2_log_levels[B2R2_LOG_LEVEL_WARN]); + (void)debugfs_create_bool("info", 0644, log_lvl_dir, + &b2r2_log_levels[B2R2_LOG_LEVEL_INFO]); + (void)debugfs_create_bool("debug", 0644, log_lvl_dir, + &b2r2_log_levels[B2R2_LOG_LEVEL_DEBUG]); + (void)debugfs_create_bool("regdumps", 0644, log_lvl_dir, + &b2r2_log_levels[B2R2_LOG_LEVEL_REGDUMP]); + +#elif defined(CONFIG_DYNAMIC_DEBUG) + /* log_lvl_dir is never used */ + (void)log_lvl_dir; +#endif + module_init++; + } + + if (cont->debugfs_debug_root_dir) { + /* No need to save the file, + * it will be removed recursively */ + (void)debugfs_create_file("last_job", 0444, + cont->debugfs_debug_root_dir, cont, + &last_job_fops); + } + + mutex_init(&cont->last_job_lock); + + return 0; +} + +void b2r2_debug_exit(void) +{ +#if !defined(CONFIG_DYNAMIC_DEBUG) && defined(CONFIG_DEBUG_FS) + module_init--; + if (!module_init && log_lvl_dir) { + debugfs_remove_recursive(log_lvl_dir); + log_lvl_dir = NULL; + } +#endif +} diff --git a/drivers/video/b2r2/b2r2_debug.h b/drivers/video/b2r2/b2r2_debug.h new file mode 100644 index 00000000000..1b1ac83f6cb --- /dev/null +++ b/drivers/video/b2r2/b2r2_debug.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 dynamic debug + * + * Author: Fredrik Allansson <fredrik.allansson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef _LINUX_DRIVERS_VIDEO_B2R2_DEBUG_H_ +#define _LINUX_DRIVERS_VIDEO_B2R2_DEBUG_H_ + +#include <linux/device.h> + +#include "b2r2_internal.h" + +#ifdef CONFIG_B2R2_DEBUG + +/* Log macros */ +enum b2r2_log_levels { + B2R2_LOG_LEVEL_WARN, + B2R2_LOG_LEVEL_INFO, + B2R2_LOG_LEVEL_DEBUG, + B2R2_LOG_LEVEL_REGDUMP, + B2R2_LOG_LEVEL_COUNT, +}; + +/* + * Booleans controlling the different log levels. The different log levels are + * enabled separately (i.e. you can have info prints without the warn prints). + */ +extern int b2r2_log_levels[B2R2_LOG_LEVEL_COUNT]; + +#define b2r2_log_err(b2r2_log_dev, ...) do { \ + dev_err(b2r2_log_dev, __VA_ARGS__); \ + } while (0) + +/* If dynamic debug is enabled it should be used instead of loglevels */ +#ifdef CONFIG_DYNAMIC_DEBUG +# define b2r2_log_warn(b2r2_log_dev, ...) do { \ + dev_dbg(b2r2_log_dev, "WARN " __VA_ARGS__); \ + } while (0) +# define b2r2_log_info(b2r2_log_dev, ...) do { \ + dev_dbg(b2r2_log_dev, "INFO " __VA_ARGS__); \ + } while (0) +# define b2r2_log_debug(b2r2_log_dev, ...) do { \ + dev_dbg(b2r2_log_dev, "DEBUG " __VA_ARGS__); \ + } while (0) +# define b2r2_log_regdump(b2r2_log_dev, ...) do { \ + dev_dbg(b2r2_log_dev, "REGD " __VA_ARGS__); \ + } while (0) +#else +# define b2r2_log_warn(b2r2_log_dev, ...) do { \ + if (b2r2_log_levels[B2R2_LOG_LEVEL_WARN]) \ + dev_warn(b2r2_log_dev, "WARN " __VA_ARGS__); \ + } while (0) +# define b2r2_log_info(b2r2_log_dev, ...) do { \ + if (b2r2_log_levels[B2R2_LOG_LEVEL_INFO]) \ + dev_info(b2r2_log_dev, "INFO " __VA_ARGS__); \ + } while (0) +# define b2r2_log_debug(b2r2_log_dev, ...) do { \ + if (b2r2_log_levels[B2R2_LOG_LEVEL_DEBUG]) \ + dev_dbg(b2r2_log_dev, "DEBUG " __VA_ARGS__); \ + } while (0) +# define b2r2_log_regdump(b2r2_log_dev, ...) do { \ + if (b2r2_log_levels[B2R2_LOG_LEVEL_REGDUMP]) \ + dev_vdbg(b2r2_log_dev, "REGD " __VA_ARGS__); \ + } while (0) +#endif + +int b2r2_debug_init(struct b2r2_control *cont); +void b2r2_debug_exit(void); +void b2r2_debug_job_done(struct b2r2_control *cont, + struct b2r2_node *node); + +#else + +#define b2r2_log_err(...) +#define b2r2_log_warn(...) +#define b2r2_log_info(...) +#define b2r2_log_debug(...) +#define b2r2_log_regdump(...) + +static inline int b2r2_debug_init(struct b2r2_control *cont) +{ + return 0; +} +static inline void b2r2_debug_exit(void) +{ + return; +} +static inline void b2r2_debug_job_done(struct b2r2_control *cont, + struct b2r2_node *node) +{ + return; +} + +#endif + +#endif diff --git a/drivers/video/b2r2/b2r2_filters.c b/drivers/video/b2r2/b2r2_filters.c new file mode 100644 index 00000000000..a969816a9e7 --- /dev/null +++ b/drivers/video/b2r2/b2r2_filters.c @@ -0,0 +1,376 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 filters. + * + * Author: Fredrik Allansson <fredrik.allansson@stericsson.com> for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/dma-mapping.h> + +#include "b2r2_filters.h" +#include "b2r2_internal.h" + +/** + * struct b2r2_filter_spec filters[] - Filter lookup table + * + * Lookup table for filters for different scale factors. A filter + * will be selected according to "min < scale_factor <= max". + */ +static struct b2r2_filter_spec filters[] = { + { + .min = 1024, + .max = 1433, + .h_coeffs = { + 0xfc, 0x06, 0xf9, 0x09, 0x34, 0x09, 0xf9, 0x06, + 0xfd, 0x07, 0xf7, 0x10, 0x32, 0x02, 0xfc, 0x05, + 0xfe, 0x07, 0xf6, 0x17, 0x2f, 0xfc, 0xff, 0x04, + 0xff, 0x06, 0xf5, 0x20, 0x2a, 0xf9, 0x01, 0x02, + 0x00, 0x04, 0xf6, 0x27, 0x25, 0xf6, 0x04, 0x00, + 0x02, 0x01, 0xf9, 0x2d, 0x1d, 0xf5, 0x06, 0xff, + 0x04, 0xff, 0xfd, 0x31, 0x15, 0xf5, 0x07, 0xfe, + 0x05, 0xfc, 0x02, 0x35, 0x0d, 0xf7, 0x07, 0xfd + }, + .v_coeffs = { + 0xf8, 0x0a, 0x3c, 0x0a, 0xf8, + 0xf6, 0x12, 0x3b, 0x02, 0xfb, + 0xf4, 0x1b, 0x35, 0xfd, 0xff, + 0xf4, 0x23, 0x30, 0xf8, 0x01, + 0xf6, 0x29, 0x27, 0xf6, 0x04, + 0xf9, 0x2e, 0x1e, 0xf5, 0x06, + 0xfd, 0x31, 0x16, 0xf6, 0x06, + 0x02, 0x32, 0x0d, 0xf8, 0x07 + }, + }, + { + .min = 1433, + .max = 1536, + .h_coeffs = { + 0xfe, 0x06, 0xf8, 0x0b, 0x30, 0x0b, 0xf8, 0x06, + 0xff, 0x06, 0xf7, 0x12, 0x2d, 0x05, 0xfa, 0x06, + 0x00, 0x04, 0xf6, 0x18, 0x2c, 0x00, 0xfc, 0x06, + 0x01, 0x02, 0xf7, 0x1f, 0x27, 0xfd, 0xff, 0x04, + 0x03, 0x00, 0xf9, 0x24, 0x24, 0xf9, 0x00, 0x03, + 0x04, 0xff, 0xfd, 0x29, 0x1d, 0xf7, 0x02, 0x01, + 0x06, 0xfc, 0x00, 0x2d, 0x17, 0xf6, 0x04, 0x00, + 0x06, 0xfa, 0x05, 0x30, 0x0f, 0xf7, 0x06, 0xff + }, + .v_coeffs = { + 0xf6, 0x0e, 0x38, 0x0e, 0xf6, + 0xf5, 0x15, 0x38, 0x06, 0xf8, + 0xf5, 0x1d, 0x33, 0x00, 0xfb, + 0xf6, 0x23, 0x2d, 0xfc, 0xfe, + 0xf9, 0x28, 0x26, 0xf9, 0x00, + 0xfc, 0x2c, 0x1e, 0xf7, 0x03, + 0x00, 0x2e, 0x18, 0xf6, 0x04, + 0x05, 0x2e, 0x11, 0xf7, 0x05 + }, + }, + { + .min = 1536, + .max = 3072, + .h_coeffs = { + 0xfc, 0xfd, 0x06, 0x13, 0x18, 0x13, 0x06, 0xfd, + 0xfc, 0xfe, 0x08, 0x15, 0x17, 0x12, 0x04, 0xfc, + 0xfb, 0xfe, 0x0a, 0x16, 0x18, 0x10, 0x03, 0xfc, + 0xfb, 0x00, 0x0b, 0x18, 0x17, 0x0f, 0x01, 0xfb, + 0xfb, 0x00, 0x0d, 0x19, 0x17, 0x0d, 0x00, 0xfb, + 0xfb, 0x01, 0x0f, 0x19, 0x16, 0x0b, 0x00, 0xfb, + 0xfc, 0x03, 0x11, 0x19, 0x15, 0x09, 0xfe, 0xfb, + 0xfc, 0x04, 0x12, 0x1a, 0x12, 0x08, 0xfe, 0xfc + }, + .v_coeffs = { + 0x05, 0x10, 0x16, 0x10, 0x05, + 0x06, 0x11, 0x16, 0x0f, 0x04, + 0x08, 0x13, 0x15, 0x0e, 0x02, + 0x09, 0x14, 0x16, 0x0c, 0x01, + 0x0b, 0x15, 0x15, 0x0b, 0x00, + 0x0d, 0x16, 0x13, 0x0a, 0x00, + 0x0f, 0x17, 0x13, 0x08, 0xff, + 0x11, 0x18, 0x12, 0x07, 0xfe + }, + }, + { + .min = 3072, + .max = 4096, + .h_coeffs = { + 0xfe, 0x02, 0x09, 0x0f, 0x0e, 0x0f, 0x09, 0x02, + 0xff, 0x02, 0x09, 0x0f, 0x10, 0x0e, 0x08, 0x01, + 0xff, 0x03, 0x0a, 0x10, 0x10, 0x0d, 0x07, 0x00, + 0x00, 0x04, 0x0b, 0x10, 0x0f, 0x0c, 0x06, 0x00, + 0x00, 0x05, 0x0c, 0x10, 0x0e, 0x0c, 0x05, 0x00, + 0x00, 0x06, 0x0c, 0x11, 0x0e, 0x0b, 0x04, 0x00, + 0x00, 0x07, 0x0d, 0x11, 0x0f, 0x0a, 0x03, 0xff, + 0x01, 0x08, 0x0e, 0x11, 0x0e, 0x09, 0x02, 0xff + }, + .v_coeffs = { + 0x09, 0x0f, 0x10, 0x0f, 0x09, + 0x09, 0x0f, 0x12, 0x0e, 0x08, + 0x0a, 0x10, 0x11, 0x0e, 0x07, + 0x0b, 0x11, 0x11, 0x0d, 0x06, + 0x0c, 0x11, 0x12, 0x0c, 0x05, + 0x0d, 0x12, 0x11, 0x0c, 0x04, + 0x0e, 0x12, 0x11, 0x0b, 0x04, + 0x0f, 0x13, 0x11, 0x0a, 0x03 + }, + }, + { + .min = 4096, + .max = 5120, + .h_coeffs = { + 0x00, 0x04, 0x09, 0x0c, 0x0e, 0x0c, 0x09, 0x04, + 0x01, 0x05, 0x09, 0x0c, 0x0d, 0x0c, 0x08, 0x04, + 0x01, 0x05, 0x0a, 0x0c, 0x0e, 0x0b, 0x08, 0x03, + 0x02, 0x06, 0x0a, 0x0d, 0x0c, 0x0b, 0x07, 0x03, + 0x02, 0x07, 0x0a, 0x0d, 0x0d, 0x0a, 0x07, 0x02, + 0x03, 0x07, 0x0b, 0x0d, 0x0c, 0x0a, 0x06, 0x02, + 0x03, 0x08, 0x0b, 0x0d, 0x0d, 0x0a, 0x05, 0x01, + 0x04, 0x08, 0x0c, 0x0d, 0x0c, 0x09, 0x05, 0x01 + }, + .v_coeffs = { + 0x0a, 0x0e, 0x10, 0x0e, 0x0a, + 0x0b, 0x0e, 0x0f, 0x0e, 0x0a, + 0x0b, 0x0f, 0x10, 0x0d, 0x09, + 0x0c, 0x0f, 0x10, 0x0d, 0x08, + 0x0d, 0x0f, 0x0f, 0x0d, 0x08, + 0x0d, 0x10, 0x10, 0x0c, 0x07, + 0x0e, 0x10, 0x0f, 0x0c, 0x07, + 0x0f, 0x10, 0x10, 0x0b, 0x06 + }, + }, +}; +static const size_t filters_size = sizeof(filters)/sizeof(filters[0]); + +/** + * struct b2r2_filter_spec bilinear_filter - A bilinear filter + * + * The bilinear filter will be used if no custom filters are specified, or + * for upscales not matching any filter in the lookup table. + */ +static struct b2r2_filter_spec bilinear_filter = { + .min = 0, + .max = 0xffff, + .h_coeffs = { + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x08, 0x3e, 0xfb, 0x00, 0x00, + 0x00, 0x00, 0xfb, 0x13, 0x3b, 0xf7, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0x1f, 0x34, 0xf5, 0x00, 0x00, + 0x00, 0x00, 0xf6, 0x2b, 0x2a, 0xf5, 0x00, 0x00, + 0x00, 0x00, 0xf6, 0x35, 0x1e, 0xf7, 0x00, 0x00, + 0x00, 0x00, 0xf9, 0x3c, 0x12, 0xf9, 0x00, 0x00, + 0x00, 0x00, 0xfd, 0x3f, 0x07, 0xfd, 0x00, 0x00 + }, + .v_coeffs = { + 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x09, 0x3d, 0xfa, 0x00, + 0x00, 0x13, 0x39, 0xf4, 0x00, + 0x00, 0x1e, 0x31, 0xf1, 0x00, + 0x00, 0x27, 0x28, 0xf1, 0x00, + 0x00, 0x31, 0x1d, 0xf2, 0x00, + 0x00, 0x38, 0x12, 0xf6, 0x00, + 0x00, 0x3d, 0x07, 0xfc, 0x00 + }, +}; + +/** + * struct b2r2_filter_spec default_downscale_filter - Default filter for downscale + * + * The default downscale filter will be used for downscales not matching any + * filter in the lookup table. + */ +static struct b2r2_filter_spec default_downscale_filter = { + .min = 1 << 10, + .max = 0xffff, + .h_coeffs = { + 0x03, 0x06, 0x09, 0x0b, 0x09, 0x0b, 0x09, 0x06, + 0x03, 0x06, 0x09, 0x0b, 0x0c, 0x0a, 0x08, 0x05, + 0x03, 0x06, 0x09, 0x0b, 0x0c, 0x0a, 0x08, 0x05, + 0x04, 0x07, 0x09, 0x0b, 0x0b, 0x0a, 0x08, 0x04, + 0x04, 0x07, 0x0a, 0x0b, 0x0b, 0x0a, 0x07, 0x04, + 0x04, 0x08, 0x0a, 0x0b, 0x0b, 0x09, 0x07, 0x04, + 0x05, 0x08, 0x0a, 0x0b, 0x0c, 0x09, 0x06, 0x03, + 0x05, 0x08, 0x0a, 0x0b, 0x0c, 0x09, 0x06, 0x03 + }, + .v_coeffs = { + 0x0b, 0x0e, 0x0e, 0x0e, 0x0b, + 0x0b, 0x0e, 0x0f, 0x0d, 0x0b, + 0x0c, 0x0e, 0x0f, 0x0d, 0x0a, + 0x0c, 0x0e, 0x0f, 0x0d, 0x0a, + 0x0d, 0x0f, 0x0e, 0x0d, 0x09, + 0x0d, 0x0f, 0x0f, 0x0c, 0x09, + 0x0e, 0x0f, 0x0e, 0x0c, 0x09, + 0x0e, 0x0f, 0x0f, 0x0c, 0x08 + }, +}; + +/** + * struct b2r2_filter_spec blur_filter - Blur filter + * + * Filter for blurring an image. + */ +static struct b2r2_filter_spec blur_filter = { + .min = 0, + .max = 0xffff, + .h_coeffs = { + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 + }, + .v_coeffs = { + 0x0c, 0x0c, 0x10, 0x0c, 0x0c, + 0x0c, 0x0c, 0x10, 0x0c, 0x0c, + 0x0c, 0x0c, 0x10, 0x0c, 0x0c, + 0x0c, 0x0c, 0x10, 0x0c, 0x0c, + 0x0c, 0x0c, 0x10, 0x0c, 0x0c, + 0x0c, 0x0c, 0x10, 0x0c, 0x0c, + 0x0c, 0x0c, 0x10, 0x0c, 0x0c, + 0x0c, 0x0c, 0x10, 0x0c, 0x0c + }, +}; + +/* Private function declarations */ +static int alloc_filter_coeffs(struct device *dev, + struct b2r2_filter_spec *filter); +static void free_filter_coeffs(struct device *dev, + struct b2r2_filter_spec *filter); + +/* Public functions */ + +int b2r2_filters_init(struct b2r2_control *cont) +{ + int i; + + if (cont->filters_initialized) + return 0; + + for (i = 0; i < filters_size; i++) { + alloc_filter_coeffs(cont->dev, &filters[i]); + } + + alloc_filter_coeffs(cont->dev, &bilinear_filter); + alloc_filter_coeffs(cont->dev, &default_downscale_filter); + alloc_filter_coeffs(cont->dev, &blur_filter); + + cont->filters_initialized = 1; + + return 0; +} + +void b2r2_filters_exit(struct b2r2_control *cont) +{ + int i; + + if (!cont->filters_initialized) + return; + + for (i = 0; i < filters_size; i++) { + free_filter_coeffs(cont->dev, &filters[i]); + } + + free_filter_coeffs(cont->dev, &bilinear_filter); + free_filter_coeffs(cont->dev, &default_downscale_filter); + free_filter_coeffs(cont->dev, &blur_filter); + + cont->filters_initialized = 0; +} + +struct b2r2_filter_spec *b2r2_filter_find(u16 scale_factor) +{ + int i; + struct b2r2_filter_spec *filter = NULL; + + for (i = 0; i < filters_size; i++) { + if ((filters[i].min < scale_factor) && + (scale_factor <= filters[i].max) && + filters[i].h_coeffs_dma_addr && + filters[i].v_coeffs_dma_addr) { + filter = &filters[i]; + break; + } + } + + if (filter == NULL) { + /* + * No suitable filter has been found. Use default filters, + * bilinear for any upscale. + */ + if (scale_factor < (1 << 10)) + filter = &bilinear_filter; + else + filter = &default_downscale_filter; + } + + /* + * Check so that the coefficients were successfully allocated for this + * filter. + */ + if (!filter->h_coeffs_dma_addr || !filter->v_coeffs_dma_addr) + return NULL; + else + return filter; +} + +struct b2r2_filter_spec *b2r2_filter_blur() +{ + return &blur_filter; +} + +/* Private functions */ +static int alloc_filter_coeffs(struct device *dev, + struct b2r2_filter_spec *filter) +{ + int ret; + + filter->h_coeffs_dma_addr = dma_alloc_coherent(dev, + B2R2_HF_TABLE_SIZE, &(filter->h_coeffs_phys_addr), + GFP_DMA | GFP_KERNEL); + if (filter->h_coeffs_dma_addr == NULL) { + ret = -ENOMEM; + goto error; + } + + filter->v_coeffs_dma_addr = dma_alloc_coherent(dev, + B2R2_VF_TABLE_SIZE, &(filter->v_coeffs_phys_addr), + GFP_DMA | GFP_KERNEL); + if (filter->v_coeffs_dma_addr == NULL) { + ret = -ENOMEM; + goto error; + } + + memcpy(filter->h_coeffs_dma_addr, filter->h_coeffs, + B2R2_HF_TABLE_SIZE); + memcpy(filter->v_coeffs_dma_addr, filter->v_coeffs, + B2R2_VF_TABLE_SIZE); + + return 0; + +error: + free_filter_coeffs(dev, filter); + return ret; + +} + +static void free_filter_coeffs(struct device *dev, + struct b2r2_filter_spec *filter) +{ + if (filter->h_coeffs_dma_addr != NULL) + dma_free_coherent(dev, B2R2_HF_TABLE_SIZE, + filter->h_coeffs_dma_addr, + filter->h_coeffs_phys_addr); + if (filter->v_coeffs_dma_addr != NULL) + dma_free_coherent(dev, B2R2_VF_TABLE_SIZE, + filter->v_coeffs_dma_addr, + filter->v_coeffs_phys_addr); + + filter->h_coeffs_dma_addr = NULL; + filter->h_coeffs_phys_addr = 0; + filter->v_coeffs_dma_addr = NULL; + filter->v_coeffs_phys_addr = 0; +} diff --git a/drivers/video/b2r2/b2r2_filters.h b/drivers/video/b2r2/b2r2_filters.h new file mode 100644 index 00000000000..790c9ec8ee9 --- /dev/null +++ b/drivers/video/b2r2/b2r2_filters.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 filters. + * + * Author: Fredrik Allansson <fredrik.allansson@stericsson.com> for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef _LINUX_VIDEO_B2R2_FILTERS_H +#define _LINUX_VIDEO_B2R2_FILTERS_H + +#include <linux/kernel.h> + +#include "b2r2_internal.h" + +#define B2R2_HF_TABLE_SIZE 64 +#define B2R2_VF_TABLE_SIZE 40 + +/** + * @struct b2r2_filter_spec - Filter specification structure + * + * @param min - Minimum scale factor for this filter (in 6.10 fixed point) + * @param max - Maximum scale factor for this filter (in 6.10 fixed point) + * @param h_coeffs - Horizontal filter coefficients + * @param v_coeffs - Vertical filter coefficients + * @param h_coeffs_dma_addr - Virtual DMA address for horizontal coefficients + * @param v_coeffs_dma_addr - Virtual DMA address for vertical coefficients + * @param h_coeffs_phys_addr - Physical address for horizontal coefficients + * @param v_coeffs_phys_addr - Physical address for vertical coefficients + */ +struct b2r2_filter_spec { + const u16 min; + const u16 max; + + const u8 h_coeffs[B2R2_HF_TABLE_SIZE]; + const u8 v_coeffs[B2R2_VF_TABLE_SIZE]; + + void *h_coeffs_dma_addr; + u32 h_coeffs_phys_addr; + + void *v_coeffs_dma_addr; + u32 v_coeffs_phys_addr; +}; + +/** + * b2r2_filters_init() - Initilizes the B2R2 filters + */ +int b2r2_filters_init(struct b2r2_control *control); + +/** + * b2r2_filters_init() - De-initilizes the B2R2 filters + */ +void b2r2_filters_exit(struct b2r2_control *control); + +/** + * b2r2_filter_find() - Find a filter matching the given scale factor + * + * @param scale_factor - Scale factor to find a filter for + * + * Returns NULL if no filter could be found. + */ +struct b2r2_filter_spec *b2r2_filter_find(u16 scale_factor); + +/** + * b2r2_filter_blur() - Returns the blur filter + * + * Returns NULL if no blur filter is available. + */ +struct b2r2_filter_spec *b2r2_filter_blur(void); + +#endif /* _LINUX_VIDEO_B2R2_FILTERS_H */ diff --git a/drivers/video/b2r2/b2r2_generic.c b/drivers/video/b2r2/b2r2_generic.c new file mode 100644 index 00000000000..1a27adbaadf --- /dev/null +++ b/drivers/video/b2r2/b2r2_generic.c @@ -0,0 +1,3334 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 generic. Full coverage of user interface but + * non optimized implementation. For Fallback purposes. + * + * Author: Maciej Socha <maciej.socha@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/debugfs.h> + +#include "b2r2_generic.h" +#include "b2r2_internal.h" +#include "b2r2_global.h" +#include "b2r2_debug.h" +#include "b2r2_filters.h" + +/* + * Debug printing + */ +#define B2R2_GENERIC_DEBUG_AREAS 0 +#define B2R2_GENERIC_DEBUG + +#define B2R2_GENERIC_WORK_BUF_WIDTH 16 +#define B2R2_GENERIC_WORK_BUF_HEIGHT 16 +#define B2R2_GENERIC_WORK_BUF_PITCH (16 * 4) +#define B2R2_GENERIC_WORK_BUF_FMT B2R2_NATIVE_ARGB8888 + +/* + * Private functions + */ + +/** + * reset_nodes() - clears the node list + */ +static void reset_nodes(struct b2r2_control *cont, + struct b2r2_node *node) +{ + b2r2_log_info(cont->dev, "%s ENTRY\n", __func__); + + while (node != NULL) { + memset(&(node->node), 0, sizeof(node->node)); + + /* TODO: Implement support for short linked lists */ + node->node.GROUP0.B2R2_CIC = 0x7fffc; + + if (node->next == NULL) + break; + + node->node.GROUP0.B2R2_NIP = node->next->physical_address; + + node = node->next; + } + b2r2_log_info(cont->dev, "%s DONE\n", __func__); +} + +/** + * dump_nodes() - prints the node list + */ +static void dump_nodes(struct b2r2_control *cont, + struct b2r2_node *first, bool dump_all) +{ + struct b2r2_node *node = first; + b2r2_log_info(cont->dev, "%s ENTRY\n", __func__); + do { + b2r2_log_debug(cont->dev, "\nNODE START:\n=============\n"); + b2r2_log_debug(cont->dev, "B2R2_ACK: \t0x%.8x\n", + node->node.GROUP0.B2R2_ACK); + b2r2_log_debug(cont->dev, "B2R2_INS: \t0x%.8x\n", + node->node.GROUP0.B2R2_INS); + b2r2_log_debug(cont->dev, "B2R2_CIC: \t0x%.8x\n", + node->node.GROUP0.B2R2_CIC); + b2r2_log_debug(cont->dev, "B2R2_NIP: \t0x%.8x\n", + node->node.GROUP0.B2R2_NIP); + + b2r2_log_debug(cont->dev, "B2R2_TSZ: \t0x%.8x\n", + node->node.GROUP1.B2R2_TSZ); + b2r2_log_debug(cont->dev, "B2R2_TXY: \t0x%.8x\n", + node->node.GROUP1.B2R2_TXY); + b2r2_log_debug(cont->dev, "B2R2_TTY: \t0x%.8x\n", + node->node.GROUP1.B2R2_TTY); + b2r2_log_debug(cont->dev, "B2R2_TBA: \t0x%.8x\n", + node->node.GROUP1.B2R2_TBA); + + b2r2_log_debug(cont->dev, "B2R2_S2CF: \t0x%.8x\n", + node->node.GROUP2.B2R2_S2CF); + b2r2_log_debug(cont->dev, "B2R2_S1CF: \t0x%.8x\n", + node->node.GROUP2.B2R2_S1CF); + + b2r2_log_debug(cont->dev, "B2R2_S1SZ: \t0x%.8x\n", + node->node.GROUP3.B2R2_SSZ); + b2r2_log_debug(cont->dev, "B2R2_S1XY: \t0x%.8x\n", + node->node.GROUP3.B2R2_SXY); + b2r2_log_debug(cont->dev, "B2R2_S1TY: \t0x%.8x\n", + node->node.GROUP3.B2R2_STY); + b2r2_log_debug(cont->dev, "B2R2_S1BA: \t0x%.8x\n", + node->node.GROUP3.B2R2_SBA); + + b2r2_log_debug(cont->dev, "B2R2_S2SZ: \t0x%.8x\n", + node->node.GROUP4.B2R2_SSZ); + b2r2_log_debug(cont->dev, "B2R2_S2XY: \t0x%.8x\n", + node->node.GROUP4.B2R2_SXY); + b2r2_log_debug(cont->dev, "B2R2_S2TY: \t0x%.8x\n", + node->node.GROUP4.B2R2_STY); + b2r2_log_debug(cont->dev, "B2R2_S2BA: \t0x%.8x\n", + node->node.GROUP4.B2R2_SBA); + + b2r2_log_debug(cont->dev, "B2R2_S3SZ: \t0x%.8x\n", + node->node.GROUP5.B2R2_SSZ); + b2r2_log_debug(cont->dev, "B2R2_S3XY: \t0x%.8x\n", + node->node.GROUP5.B2R2_SXY); + b2r2_log_debug(cont->dev, "B2R2_S3TY: \t0x%.8x\n", + node->node.GROUP5.B2R2_STY); + b2r2_log_debug(cont->dev, "B2R2_S3BA: \t0x%.8x\n", + node->node.GROUP5.B2R2_SBA); + + b2r2_log_debug(cont->dev, "B2R2_CWS: \t0x%.8x\n", + node->node.GROUP6.B2R2_CWS); + b2r2_log_debug(cont->dev, "B2R2_CWO: \t0x%.8x\n", + node->node.GROUP6.B2R2_CWO); + + b2r2_log_debug(cont->dev, "B2R2_FCTL: \t0x%.8x\n", + node->node.GROUP8.B2R2_FCTL); + b2r2_log_debug(cont->dev, "B2R2_RSF: \t0x%.8x\n", + node->node.GROUP9.B2R2_RSF); + b2r2_log_debug(cont->dev, "B2R2_RZI: \t0x%.8x\n", + node->node.GROUP9.B2R2_RZI); + b2r2_log_debug(cont->dev, "B2R2_HFP: \t0x%.8x\n", + node->node.GROUP9.B2R2_HFP); + b2r2_log_debug(cont->dev, "B2R2_VFP: \t0x%.8x\n", + node->node.GROUP9.B2R2_VFP); + b2r2_log_debug(cont->dev, "B2R2_LUMA_RSF: \t0x%.8x\n", + node->node.GROUP10.B2R2_RSF); + b2r2_log_debug(cont->dev, "B2R2_LUMA_RZI: \t0x%.8x\n", + node->node.GROUP10.B2R2_RZI); + b2r2_log_debug(cont->dev, "B2R2_LUMA_HFP: \t0x%.8x\n", + node->node.GROUP10.B2R2_HFP); + b2r2_log_debug(cont->dev, "B2R2_LUMA_VFP: \t0x%.8x\n", + node->node.GROUP10.B2R2_VFP); + + + b2r2_log_debug(cont->dev, "B2R2_IVMX0: \t0x%.8x\n", + node->node.GROUP15.B2R2_VMX0); + b2r2_log_debug(cont->dev, "B2R2_IVMX1: \t0x%.8x\n", + node->node.GROUP15.B2R2_VMX1); + b2r2_log_debug(cont->dev, "B2R2_IVMX2: \t0x%.8x\n", + node->node.GROUP15.B2R2_VMX2); + b2r2_log_debug(cont->dev, "B2R2_IVMX3: \t0x%.8x\n", + node->node.GROUP15.B2R2_VMX3); + b2r2_log_debug(cont->dev, "\n=============\nNODE END\n"); + + node = node->next; + } while (node != NULL && dump_all); + + b2r2_log_info(cont->dev, "%s DONE\n", __func__); +} + +/** + * to_native_fmt() - returns the native B2R2 format + */ +static inline enum b2r2_native_fmt to_native_fmt(struct b2r2_control *cont, + enum b2r2_blt_fmt fmt) +{ + + switch (fmt) { + case B2R2_BLT_FMT_UNUSED: + return B2R2_NATIVE_RGB565; + case B2R2_BLT_FMT_1_BIT_A1: + return B2R2_NATIVE_A1; + case B2R2_BLT_FMT_8_BIT_A8: + return B2R2_NATIVE_A8; + case B2R2_BLT_FMT_16_BIT_RGB565: + return B2R2_NATIVE_RGB565; + case B2R2_BLT_FMT_16_BIT_ARGB4444: + return B2R2_NATIVE_ARGB4444; + case B2R2_BLT_FMT_16_BIT_ARGB1555: + return B2R2_NATIVE_ARGB1555; + case B2R2_BLT_FMT_24_BIT_ARGB8565: + return B2R2_NATIVE_ARGB8565; + case B2R2_BLT_FMT_24_BIT_RGB888: + return B2R2_NATIVE_RGB888; + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_24_BIT_YUV888: + return B2R2_NATIVE_YCBCR888; + case B2R2_BLT_FMT_32_BIT_ABGR8888: /* Not actually supported by HW */ + case B2R2_BLT_FMT_32_BIT_ARGB8888: + return B2R2_NATIVE_ARGB8888; + case B2R2_BLT_FMT_32_BIT_VUYA8888: /* fall through */ + case B2R2_BLT_FMT_32_BIT_AYUV8888: + return B2R2_NATIVE_AYCBCR8888; + case B2R2_BLT_FMT_CB_Y_CR_Y: + return B2R2_NATIVE_YCBCR422R; + case B2R2_BLT_FMT_Y_CB_Y_CR: + return B2R2_NATIVE_YCBCR422R; + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + return B2R2_NATIVE_YCBCR42X_R2B; + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + return B2R2_NATIVE_YCBCR42X_MBN; + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + return B2R2_NATIVE_YUV; + default: + /* Should never ever happen */ + return B2R2_NATIVE_BYTE; + } +} + +/** + * get_alpha_range() - returns the alpha range of the given format + */ +static inline enum b2r2_ty get_alpha_range(struct b2r2_control *cont, + enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_24_BIT_ARGB8565: + case B2R2_BLT_FMT_32_BIT_ARGB8888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + case B2R2_BLT_FMT_8_BIT_A8: + case B2R2_BLT_FMT_32_BIT_ABGR8888: + return B2R2_TY_ALPHA_RANGE_255; /* 0 - 255 */ + break; + default: + break; + } + + return B2R2_TY_ALPHA_RANGE_128; /* 0 - 128 */ +} + +static unsigned int get_pitch(struct b2r2_control *cont, + enum b2r2_blt_fmt format, u32 width) +{ + switch (format) { + case B2R2_BLT_FMT_1_BIT_A1: { + int pitch = width >> 3; + /* Check for remainder */ + if (width & 7) + pitch++; + return pitch; + break; + } + case B2R2_BLT_FMT_8_BIT_A8: + return width; + break; + case B2R2_BLT_FMT_16_BIT_RGB565: /* all 16 bits/pixel RGB formats */ + case B2R2_BLT_FMT_16_BIT_ARGB1555: + case B2R2_BLT_FMT_16_BIT_ARGB4444: + return width * 2; + break; + case B2R2_BLT_FMT_24_BIT_RGB888: /* all 24 bits/pixel raster formats */ + case B2R2_BLT_FMT_24_BIT_ARGB8565: + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_24_BIT_VUY888: + return width * 3; + break; + case B2R2_BLT_FMT_32_BIT_ARGB8888: /* all 32 bits/pixel formats */ + case B2R2_BLT_FMT_32_BIT_ABGR8888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + return width * 4; + break; + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + /* width of the buffer must be a multiple of 4 */ + if (width & 3) { + b2r2_log_warn(cont->dev, "%s: Illegal width " + "for fmt=%#010x width=%d\n", __func__, + format, width); + return 0; + } + return width * 2; + break; + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + return width; + break; + /* fall through, same pitch and pointers */ + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + /* width of the buffer must be a multiple of 2 */ + if (width & 1) { + b2r2_log_warn(cont->dev, "%s: Illegal width " + "for fmt=%#010x width=%d\n", __func__, + format, width); + return 0; + } + /* + * return pitch of the Y-buffer. + * U and V pitch can be derived from it. + */ + return width; + break; + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + /* width of the buffer must be a multiple of 16. */ + if (width & 15) { + b2r2_log_warn(cont->dev, "%s: Illegal width " + "for fmt=%#010x width=%d\n", __func__, + format, width); + return 0; + } + /* + * return pitch of the Y-buffer. + * U and V pitch can be derived from it. + */ + return width; + break; + default: + b2r2_log_warn(cont->dev, "%s: Unable to determine pitch " + "for fmt=%#010x width=%d\n", __func__, + format, width); + return 0; + } +} + +static s32 validate_buf(struct b2r2_control *cont, + const struct b2r2_blt_img *image, + const struct b2r2_resolved_buf *buf) +{ + u32 expect_buf_size; + u32 pitch; + + if (image->width <= 0 || image->height <= 0) { + b2r2_log_warn(cont->dev, "%s: width=%d or height=%d negative" + ".\n", __func__, image->width, image->height); + return -EINVAL; + } + + if (image->pitch == 0) { + /* autodetect pitch based on format and width */ + pitch = get_pitch(cont, image->fmt, image->width); + } else + pitch = image->pitch; + + expect_buf_size = pitch * image->height; + + if (pitch == 0) { + b2r2_log_warn(cont->dev, "%s: Unable to detect pitch. " + "fmt=%#010x, width=%d\n", + __func__, + image->fmt, image->width); + return -EINVAL; + } + + /* format specific adjustments */ + switch (image->fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + /* + * Use ceil(height/2) in case buffer height + * is not divisible by 2. + */ + expect_buf_size += + (pitch >> 1) * ((image->height + 1) >> 1) * 2; + break; + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + expect_buf_size += (pitch >> 1) * image->height * 2; + break; + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + expect_buf_size += pitch * image->height * 2; + break; + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + /* + * include space occupied by U and V data. + * U and V interleaved, half resolution, which makes + * the UV pitch equal to luma pitch. + * Use ceil(height/2) in case buffer height + * is not divisible by 2. + */ + expect_buf_size += pitch * ((image->height + 1) >> 1); + break; + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + /* + * include space occupied by U and V data. + * U and V interleaved, half resolution, which makes + * the UV pitch equal to luma pitch. + */ + expect_buf_size += pitch * image->height; + break; + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + /* Height must be a multiple of 16 for macro-block format.*/ + if (image->height & 15) { + b2r2_log_warn(cont->dev, "%s: Illegal height " + "for fmt=%#010x height=%d\n", __func__, + image->fmt, image->height); + return -EINVAL; + } + expect_buf_size += pitch * (image->height >> 1); + break; + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + /* Height must be a multiple of 16 for macro-block format.*/ + if (image->height & 15) { + b2r2_log_warn(cont->dev, "%s: Illegal height " + "for fmt=%#010x height=%d\n", __func__, + image->fmt, image->height); + return -EINVAL; + } + expect_buf_size += pitch * image->height; + break; + default: + break; + } + + if (buf->file_len < expect_buf_size) { + b2r2_log_warn(cont->dev, "%s: Invalid buffer size:\n" + "fmt=%#010x w=%d h=%d buf.len=%d expect_buf_size=%d\n", + __func__, + image->fmt, image->width, image->height, buf->file_len, + expect_buf_size); + return -EINVAL; + } + + if (image->buf.type == B2R2_BLT_PTR_VIRTUAL) { + b2r2_log_warn(cont->dev, "%s: Virtual pointers not supported" + " yet.\n", __func__); + return -EINVAL; + } + return 0; +} + +/* + * Bit-expand the color from fmt to RGB888 with blue at LSB. + * Copy MSBs into missing LSBs. + */ +static u32 to_RGB888(struct b2r2_control *cont, u32 color, + const enum b2r2_blt_fmt fmt) +{ + u32 out_color = 0; + u32 r = 0; + u32 g = 0; + u32 b = 0; + switch (fmt) { + case B2R2_BLT_FMT_16_BIT_ARGB4444: + r = ((color & 0xf00) << 12) | ((color & 0xf00) << 8); + g = ((color & 0xf0) << 8) | ((color & 0xf0) << 4); + b = ((color & 0xf) << 4) | (color & 0xf); + out_color = r | g | b; + break; + case B2R2_BLT_FMT_16_BIT_ARGB1555: + r = ((color & 0x7c00) << 9) | ((color & 0x7000) << 4); + g = ((color & 0x3e0) << 6) | ((color & 0x380) << 1); + b = ((color & 0x1f) << 3) | ((color & 0x1c) >> 2); + out_color = r | g | b; + break; + case B2R2_BLT_FMT_16_BIT_RGB565: + r = ((color & 0xf800) << 8) | ((color & 0xe000) << 3); + g = ((color & 0x7e0) << 5) | ((color & 0x600) >> 1); + b = ((color & 0x1f) << 3) | ((color & 0x1c) >> 2); + out_color = r | g | b; + break; + case B2R2_BLT_FMT_24_BIT_RGB888: + case B2R2_BLT_FMT_32_BIT_ARGB8888: + out_color = color & 0xffffff; + break; + case B2R2_BLT_FMT_32_BIT_ABGR8888: + r = (color & 0xff) << 16; + g = color & 0xff00; + b = (color & 0xff0000) >> 16; + out_color = r | g | b; + break; + case B2R2_BLT_FMT_24_BIT_ARGB8565: + r = ((color & 0xf800) << 8) | ((color & 0xe000) << 3); + g = ((color & 0x7e0) << 5) | ((color & 0x600) >> 1); + b = ((color & 0x1f) << 3) | ((color & 0x1c) >> 2); + out_color = r | g | b; + break; + default: + break; + } + + return out_color; +} + + +static void setup_fill_input_stage(const struct b2r2_blt_request *req, + struct b2r2_node *node, + struct b2r2_work_buf *out_buf) +{ + enum b2r2_native_fmt fill_fmt = 0; + u32 src_color = req->user_req.src_color; + const struct b2r2_blt_img *dst_img = &(req->user_req.dst_img); + struct b2r2_control *cont = req->instance->control; + + b2r2_log_info(cont->dev, "%s ENTRY\n", __func__); + + /* Determine format in src_color */ + switch (dst_img->fmt) { + /* ARGB formats */ + case B2R2_BLT_FMT_16_BIT_ARGB4444: + case B2R2_BLT_FMT_16_BIT_ARGB1555: + case B2R2_BLT_FMT_16_BIT_RGB565: + case B2R2_BLT_FMT_24_BIT_RGB888: + case B2R2_BLT_FMT_32_BIT_ARGB8888: + case B2R2_BLT_FMT_32_BIT_ABGR8888: + case B2R2_BLT_FMT_24_BIT_ARGB8565: + case B2R2_BLT_FMT_1_BIT_A1: + case B2R2_BLT_FMT_8_BIT_A8: + if ((req->user_req.flags & B2R2_BLT_FLAG_SOURCE_FILL) != 0) { + fill_fmt = B2R2_NATIVE_ARGB8888; + } else { + /* SOURCE_FILL_RAW */ + fill_fmt = to_native_fmt(cont, dst_img->fmt); + if (dst_img->fmt == B2R2_BLT_FMT_32_BIT_ABGR8888) { + /* + * Color is read from a register, + * where it is stored in ABGR format. + * Set up IVMX. + */ + node->node.GROUP0.B2R2_INS |= + B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_RGB_TO_BGR; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_RGB_TO_BGR; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_RGB_TO_BGR; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_RGB_TO_BGR; + } + } + break; + /* YUV formats */ + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + if ((req->user_req.flags & B2R2_BLT_FLAG_SOURCE_FILL) != 0) { + fill_fmt = B2R2_NATIVE_AYCBCR8888; + /* + * Set up IVMX + * The destination format is in fact YUV, + * but the input stage stores the data in + * an intermediate buffer which is RGB. + * Hence the conversion from YUV to RGB. + * Format of the supplied src_color is + * B2R2_BLT_FMT_32_BIT_AYUV8888. + */ + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_BLT_YUV888_TO_RGB_601_VIDEO; + } else { + /* SOURCE_FILL_RAW */ + bool dst_yuv_planar = + B2R2_BLT_FMT_YUV420_PACKED_PLANAR == + dst_img->fmt || + B2R2_BLT_FMT_YUV422_PACKED_PLANAR == + dst_img->fmt || + B2R2_BLT_FMT_YVU420_PACKED_PLANAR == + dst_img->fmt || + B2R2_BLT_FMT_YVU422_PACKED_PLANAR == + dst_img->fmt || + B2R2_BLT_FMT_YUV444_PACKED_PLANAR == + dst_img->fmt; + + bool dst_yuv_semi_planar = + B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR == + dst_img->fmt || + B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR == + dst_img->fmt || + B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR == + dst_img->fmt || + B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR == + dst_img->fmt || + B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE == + dst_img->fmt || + B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE == + dst_img->fmt; + + if (dst_yuv_planar || dst_yuv_semi_planar) { + /* + * SOURCE_FILL_RAW cannot be supported + * with multi-buffer formats. + * Force a legal format to prevent B2R2 + * from misbehaving. + */ + fill_fmt = B2R2_NATIVE_AYCBCR8888; + } else { + fill_fmt = to_native_fmt(cont, dst_img->fmt); + } + + switch (dst_img->fmt) { + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + node->node.GROUP0.B2R2_INS |= + B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_BLT_YUV888_TO_RGB_601_VIDEO; + /* + * Re-arrange the color components from + * VUY(A) to (A)YUV + */ + if (dst_img->fmt == + B2R2_BLT_FMT_24_BIT_VUY888) { + u32 Y = src_color & 0xff; + u32 U = src_color & 0xff00; + u32 V = src_color & 0xff0000; + src_color = (Y << 16) | U | (V >> 16); + } else if (dst_img->fmt == + B2R2_BLT_FMT_32_BIT_VUYA8888) { + u32 A = src_color & 0xff; + u32 Y = src_color & 0xff00; + u32 U = src_color & 0xff0000; + u32 V = src_color & 0xff000000; + src_color = (A << 24) | + (Y << 8) | + (U >> 8) | + (V >> 24); + } + break; + case B2R2_BLT_FMT_Y_CB_Y_CR: + /* + * Setup input VMX to convert YVU to + * RGB 601 VIDEO + * Chroma components are swapped so + * it is YVU and not YUV. + */ + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_YVU_TO_RGB_601_VIDEO; + break; + default: + /* + * Set up IVMX + * The destination format is in fact YUV, + * but the input stage stores the data in + * an intermediate buffer which is RGB. + * Hence the conversion from YUV to RGB. + */ + node->node.GROUP0.B2R2_INS |= + B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_YUV_TO_RGB_601_VIDEO; + break; + } + } + break; + default: + src_color = 0; + fill_fmt = B2R2_NATIVE_ARGB8888; + break; + } + + node->node.GROUP1.B2R2_TBA = out_buf->phys_addr; + node->node.GROUP1.B2R2_TTY = + (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) | + B2R2_GENERIC_WORK_BUF_FMT | + B2R2_TY_ALPHA_RANGE_255 | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + /* Set color fill on SRC2 channel */ + node->node.GROUP4.B2R2_SBA = 0; + node->node.GROUP4.B2R2_STY = + (0 << B2R2_TY_BITMAP_PITCH_SHIFT) | + fill_fmt | + get_alpha_range(cont, dst_img->fmt) | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + node->node.GROUP0.B2R2_INS |= + B2R2_INS_SOURCE_2_COLOR_FILL_REGISTER; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_COLOR_FILL; + node->node.GROUP2.B2R2_S2CF = src_color; + + node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BYPASS_S2_S3; + b2r2_log_info(cont->dev, "%s DONE\n", __func__); +} + +static void setup_input_stage(const struct b2r2_blt_request *req, + struct b2r2_node *node, + struct b2r2_work_buf *out_buf) +{ + /* Horizontal and vertical scaling factors in 6.10 fixed point format */ + s32 h_scf = 1 << 10; + s32 v_scf = 1 << 10; + const struct b2r2_blt_rect *src_rect = &(req->user_req.src_rect); + const struct b2r2_blt_rect *dst_rect = &(req->user_req.dst_rect); + const struct b2r2_blt_img *src_img = &(req->user_req.src_img); + u32 src_pitch = 0; + /* horizontal and vertical scan order for out_buf */ + enum b2r2_ty dst_hso = B2R2_TY_HSO_LEFT_TO_RIGHT; + enum b2r2_ty dst_vso = B2R2_TY_VSO_TOP_TO_BOTTOM; + u32 endianness = 0; + u32 fctl = 0; + u32 rsf = 0; + u32 rzi = 0; + bool yuv_semi_planar = + src_img->fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR || + src_img->fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR || + src_img->fmt == B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR || + src_img->fmt == B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR || + src_img->fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE || + src_img->fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE; + + bool yuv_planar = + src_img->fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR || + src_img->fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR || + src_img->fmt == B2R2_BLT_FMT_YVU420_PACKED_PLANAR || + src_img->fmt == B2R2_BLT_FMT_YVU422_PACKED_PLANAR || + src_img->fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR; + + struct b2r2_filter_spec *hf; + struct b2r2_filter_spec *vf; + + bool use_h_filter = false; + bool use_v_filter = false; + + struct b2r2_control *cont = req->instance->control; + + b2r2_log_info(cont->dev, "%s ENTRY\n", __func__); + + if (((B2R2_BLT_FLAG_SOURCE_FILL | B2R2_BLT_FLAG_SOURCE_FILL_RAW) & + req->user_req.flags) != 0) { + setup_fill_input_stage(req, node, out_buf); + b2r2_log_info(cont->dev, "%s DONE\n", __func__); + return; + } + + if (src_img->pitch == 0) { + /* Determine pitch based on format and width of the image. */ + src_pitch = get_pitch(cont, src_img->fmt, src_img->width); + } else { + src_pitch = src_img->pitch; + } + + b2r2_log_info(cont->dev, "%s transform=%#010x\n", + __func__, req->user_req.transform); + if (req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) { + h_scf = (src_rect->width << 10) / dst_rect->height; + v_scf = (src_rect->height << 10) / dst_rect->width; + } else { + h_scf = (src_rect->width << 10) / dst_rect->width; + v_scf = (src_rect->height << 10) / dst_rect->height; + } + + hf = b2r2_filter_find(h_scf); + vf = b2r2_filter_find(v_scf); + + use_h_filter = h_scf != (1 << 10); + use_v_filter = v_scf != (1 << 10); + + /* B2R2_BLT_FLAG_BLUR overrides any scaling filter. */ + if (req->user_req.flags & B2R2_BLT_FLAG_BLUR) { + use_h_filter = true; + use_v_filter = true; + hf = b2r2_filter_blur(); + vf = b2r2_filter_blur(); + } + + /* Configure horizontal rescale */ + if (h_scf != (1 << 10)) { + b2r2_log_info(cont->dev, "%s: Scaling horizontally by 0x%.8x" + "\ns(%d, %d)->d(%d, %d)\n", __func__, + h_scf, src_rect->width, src_rect->height, + dst_rect->width, dst_rect->height); + } + fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER; + rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT); + rsf |= h_scf << B2R2_RSF_HSRC_INC_SHIFT; + rzi |= B2R2_RZI_DEFAULT_HNB_REPEAT; + + /* Configure vertical rescale */ + if (v_scf != (1 << 10)) { + b2r2_log_info(cont->dev, "%s: Scaling vertically by 0x%.8x" + "\ns(%d, %d)->d(%d, %d)\n", __func__, + v_scf, src_rect->width, src_rect->height, + dst_rect->width, dst_rect->height); + } + fctl |= B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER; + rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT); + rsf |= v_scf << B2R2_RSF_VSRC_INC_SHIFT; + rzi |= 2 << B2R2_RZI_VNB_REPEAT_SHIFT; + + node->node.GROUP0.B2R2_INS |= B2R2_INS_RESCALE2D_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_RESIZE_CHROMA; + + /* Adjustments that depend on the source format */ + switch (src_img->fmt) { + case B2R2_BLT_FMT_32_BIT_ABGR8888: + /* Set up IVMX */ + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + + node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_RGB_TO_BGR; + node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_RGB_TO_BGR; + node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_RGB_TO_BGR; + node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_RGB_TO_BGR; + break; + case B2R2_BLT_FMT_Y_CB_Y_CR: + /* + * Setup input VMX to convert YVU to RGB 601 VIDEO + * Chroma components are swapped so + * it is YVU and not YUV. + */ + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_YVU_TO_RGB_601_VIDEO; + break; + case B2R2_BLT_FMT_CB_Y_CR_Y: + /* Set up IVMX */ + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_YUV_TO_RGB_601_VIDEO; + break; + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + /* + * Set up IVMX. + * For B2R2_BLT_FMT_32_BIT_YUV888 and + * B2R2_BLT_FMT_32_BIT_AYUV8888 + * the color components are laid out in memory as V, U, Y, (A) + * with V at the first byte (due to little endian addressing). + * B2R2 expects them to be as U, Y, V, (A) + * with U at the first byte. + */ + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_BLT_YUV888_TO_RGB_601_VIDEO; + + /* + * Re-arrange color components from VUY(A) to (A)YUV + * for input VMX to work on them further. + */ + if (src_img->fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + src_img->fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) + endianness = B2R2_TY_ENDIAN_BIG_NOT_LITTLE; + break; + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: { + /* + * Luma handled in the same way + * for all YUV multi-buffer formats. + * Set luma rescale registers. + */ + u32 rsf_luma = 0; + u32 rzi_luma = 0; + + /* Set up IVMX */ + node->node.GROUP0.B2R2_INS |= + B2R2_INS_IVMX_ENABLED | B2R2_INS_RESCALE2D_ENABLED; + node->node.GROUP0.B2R2_CIC |= + B2R2_CIC_IVMX | B2R2_CIC_RESIZE_LUMA; + + if (src_img->fmt == B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR || + src_img->fmt == + B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR) { + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_YVU_TO_RGB_601_VIDEO; + } else { + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_YUV_TO_RGB_601_VIDEO; + } + + fctl |= B2R2_FCTL_LUMA_HF2D_MODE_ENABLE_RESIZER | + B2R2_FCTL_LUMA_VF2D_MODE_ENABLE_RESIZER; + + if (use_h_filter && hf) { + fctl |= B2R2_FCTL_LUMA_HF2D_MODE_ENABLE_FILTER; + node->node.GROUP10.B2R2_HFP = hf->h_coeffs_phys_addr; + } + + if (use_v_filter && vf) { + fctl |= B2R2_FCTL_LUMA_VF2D_MODE_ENABLE_FILTER; + node->node.GROUP10.B2R2_VFP = vf->v_coeffs_phys_addr; + } + + rsf_luma |= h_scf << B2R2_RSF_HSRC_INC_SHIFT; + rzi_luma |= B2R2_RZI_DEFAULT_HNB_REPEAT; + + rsf_luma |= v_scf << B2R2_RSF_VSRC_INC_SHIFT; + rzi_luma |= 2 << B2R2_RZI_VNB_REPEAT_SHIFT; + + node->node.GROUP10.B2R2_RSF = rsf_luma; + node->node.GROUP10.B2R2_RZI = rzi_luma; + + switch (src_img->fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + /* + * Chrominance is always half the luminance size + * so chrominance resizer is always active. + */ + fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER | + B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER; + + rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT); + rsf |= (h_scf >> 1) << B2R2_RSF_HSRC_INC_SHIFT; + rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT); + rsf |= (v_scf >> 1) << B2R2_RSF_VSRC_INC_SHIFT; + /* Select suitable filter for chroma */ + hf = b2r2_filter_find(h_scf >> 1); + vf = b2r2_filter_find(v_scf >> 1); + use_h_filter = true; + use_v_filter = true; + break; + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + /* + * Chrominance is always half the luminance size + * only in horizontal direction. + */ + fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER | + B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER; + + rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT); + rsf |= (h_scf >> 1) << B2R2_RSF_HSRC_INC_SHIFT; + rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT); + rsf |= v_scf << B2R2_RSF_VSRC_INC_SHIFT; + /* Select suitable filter for chroma */ + hf = b2r2_filter_find(h_scf >> 1); + use_h_filter = true; + break; + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + /* Chrominance is the same size as luminance.*/ + fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER | + B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER; + + rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT); + rsf |= h_scf << B2R2_RSF_HSRC_INC_SHIFT; + rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT); + rsf |= v_scf << B2R2_RSF_VSRC_INC_SHIFT; + /* Select suitable filter for chroma */ + hf = b2r2_filter_find(h_scf); + vf = b2r2_filter_find(v_scf); + use_h_filter = true; + use_v_filter = true; + break; + default: + break; + } + break; + } + default: + break; + } + + /* + * Set the filter control and rescale registers. + * GROUP9 registers are used for all single-buffer formats + * or for chroma in case of multi-buffer YUV formats. + * h/v_filter is now appropriately selected for chroma scaling, + * be it YUV multi-buffer, or single-buffer raster format. + * B2R2_BLT_FLAG_BLUR overrides any scaling filter. + */ + if (req->user_req.flags & B2R2_BLT_FLAG_BLUR) { + use_h_filter = true; + use_v_filter = true; + hf = b2r2_filter_blur(); + vf = b2r2_filter_blur(); + } + + if (use_h_filter && hf) { + fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_COLOR_CHANNEL_FILTER; + node->node.GROUP9.B2R2_HFP = hf->h_coeffs_phys_addr; + } + + if (use_v_filter && vf) { + fctl |= B2R2_FCTL_VF2D_MODE_ENABLE_COLOR_CHANNEL_FILTER; + node->node.GROUP9.B2R2_VFP = vf->v_coeffs_phys_addr; + } + + node->node.GROUP8.B2R2_FCTL |= fctl; + node->node.GROUP9.B2R2_RSF |= rsf; + node->node.GROUP9.B2R2_RZI |= rzi; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_FILTER_CONTROL; + + /* + * Flip transform is done before potential rotation. + * This can be achieved with appropriate scan order. + * Transform stage will only do rotation. + */ + if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_H) + dst_hso = B2R2_TY_HSO_RIGHT_TO_LEFT; + + if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_V) + dst_vso = B2R2_TY_VSO_BOTTOM_TO_TOP; + + /* Set target buffer */ + node->node.GROUP1.B2R2_TBA = out_buf->phys_addr; + node->node.GROUP1.B2R2_TTY = + (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) | + B2R2_GENERIC_WORK_BUF_FMT | + B2R2_TY_ALPHA_RANGE_255 | + dst_hso | dst_vso; + + if (yuv_planar) { + /* + * Set up chrominance buffers on source 1 and 2, + * luminance on source 3. + * src_pitch and physical_address apply to luminance, + * corresponding chrominance values have to be derived. + */ + u32 cb_addr = 0; + u32 cr_addr = 0; + u32 chroma_pitch = 0; + bool swapped_chroma = + src_img->fmt == B2R2_BLT_FMT_YVU420_PACKED_PLANAR || + src_img->fmt == B2R2_BLT_FMT_YVU422_PACKED_PLANAR; + enum b2r2_native_fmt src_fmt = + to_native_fmt(cont, src_img->fmt); + + if (swapped_chroma) + cr_addr = req->src_resolved.physical_address + + src_pitch * src_img->height; + else + cb_addr = req->src_resolved.physical_address + + src_pitch * src_img->height; + + switch (src_img->fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + chroma_pitch = src_pitch >> 1; + if (swapped_chroma) + cb_addr = cr_addr + chroma_pitch * + (src_img->height >> 1); + else + cr_addr = cb_addr + chroma_pitch * + (src_img->height >> 1); + break; + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + chroma_pitch = src_pitch >> 1; + if (swapped_chroma) + cb_addr = cr_addr + chroma_pitch * + src_img->height; + else + cr_addr = cb_addr + chroma_pitch * + src_img->height; + break; + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + /* Chrominance has full resolution, same as luminance.*/ + chroma_pitch = src_pitch; + cr_addr = + cb_addr + chroma_pitch * src_img->height; + break; + default: + break; + } + + node->node.GROUP3.B2R2_SBA = cr_addr; + node->node.GROUP3.B2R2_STY = + (chroma_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + src_fmt | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + node->node.GROUP4.B2R2_SBA = cb_addr; + node->node.GROUP4.B2R2_STY = node->node.GROUP3.B2R2_STY; + + node->node.GROUP5.B2R2_SBA = req->src_resolved.physical_address; + node->node.GROUP5.B2R2_STY = + (src_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + src_fmt | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + node->node.GROUP0.B2R2_INS |= + B2R2_INS_SOURCE_1_FETCH_FROM_MEM | + B2R2_INS_SOURCE_2_FETCH_FROM_MEM | + B2R2_INS_SOURCE_3_FETCH_FROM_MEM; + node->node.GROUP0.B2R2_CIC |= + B2R2_CIC_SOURCE_1 | + B2R2_CIC_SOURCE_2 | + B2R2_CIC_SOURCE_3; + } else if (yuv_semi_planar) { + /* + * Set up chrominance buffer on source 2, luminance on source 3. + * src_pitch and physical_address apply to luminance, + * corresponding chrominance values have to be derived. + * U and V are interleaved at half the luminance resolution, + * which makes the pitch of the UV plane equal + * to luminance pitch. + */ + u32 chroma_addr = req->src_resolved.physical_address + + src_pitch * src_img->height; + u32 chroma_pitch = src_pitch; + + enum b2r2_native_fmt src_fmt = + to_native_fmt(cont, src_img->fmt); + + node->node.GROUP4.B2R2_SBA = chroma_addr; + node->node.GROUP4.B2R2_STY = + (chroma_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + src_fmt | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + node->node.GROUP5.B2R2_SBA = req->src_resolved.physical_address; + node->node.GROUP5.B2R2_STY = + (src_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + src_fmt | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + node->node.GROUP0.B2R2_INS |= + B2R2_INS_SOURCE_2_FETCH_FROM_MEM | + B2R2_INS_SOURCE_3_FETCH_FROM_MEM; + node->node.GROUP0.B2R2_CIC |= + B2R2_CIC_SOURCE_2 | B2R2_CIC_SOURCE_3; + } else { + /* single buffer format */ + node->node.GROUP4.B2R2_SBA = req->src_resolved.physical_address; + node->node.GROUP4.B2R2_STY = + (src_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + to_native_fmt(cont, src_img->fmt) | + get_alpha_range(cont, src_img->fmt) | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM | + endianness; + + node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_2_FETCH_FROM_MEM; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2; + } + + if ((req->user_req.flags & + B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) != 0) { + node->node.GROUP0.B2R2_INS |= B2R2_INS_CLUTOP_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_CLUT; + node->node.GROUP7.B2R2_CCO = B2R2_CCO_CLUT_COLOR_CORRECTION | + B2R2_CCO_CLUT_UPDATE; + node->node.GROUP7.B2R2_CML = req->clut_phys_addr; + } + + node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BYPASS_S2_S3; + + b2r2_log_info(cont->dev, "%s DONE\n", __func__); +} + +static void setup_transform_stage(const struct b2r2_blt_request *req, + struct b2r2_node *node, + struct b2r2_work_buf *out_buf, + struct b2r2_work_buf *in_buf) +{ + /* vertical scan order for out_buf */ + enum b2r2_ty dst_vso = B2R2_TY_VSO_TOP_TO_BOTTOM; + enum b2r2_blt_transform transform = req->user_req.transform; +#ifdef CONFIG_B2R2_DEBUG + struct b2r2_control *cont = req->instance->control; +#endif + + b2r2_log_info(cont->dev, "%s ENTRY\n", __func__); + + if (transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) { + /* + * Scan order must be flipped otherwise contents will + * be mirrored vertically. Leftmost column of in_buf + * would become top instead of bottom row of out_buf. + */ + dst_vso = B2R2_TY_VSO_BOTTOM_TO_TOP; + node->node.GROUP0.B2R2_INS |= B2R2_INS_ROTATION_ENABLED; + } + + /* Set target buffer */ + node->node.GROUP1.B2R2_TBA = out_buf->phys_addr; + node->node.GROUP1.B2R2_TTY = + (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) | + B2R2_GENERIC_WORK_BUF_FMT | + B2R2_TY_ALPHA_RANGE_255 | + B2R2_TY_HSO_LEFT_TO_RIGHT | dst_vso; + + /* Set source buffer on SRC2 channel */ + node->node.GROUP4.B2R2_SBA = in_buf->phys_addr; + node->node.GROUP4.B2R2_STY = + (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) | + B2R2_GENERIC_WORK_BUF_FMT | + B2R2_TY_ALPHA_RANGE_255 | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_2_FETCH_FROM_MEM; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2; + node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BYPASS_S2_S3; + + b2r2_log_info(cont->dev, "%s DONE\n", __func__); +} + +/* +static void setup_mask_stage(const struct b2r2_blt_request req, + struct b2r2_node *node, + struct b2r2_work_buf *out_buf, + struct b2r2_work_buf *in_buf); +*/ + +static void setup_dst_read_stage(const struct b2r2_blt_request *req, + struct b2r2_node *node, + struct b2r2_work_buf *out_buf) +{ + const struct b2r2_blt_img *dst_img = &(req->user_req.dst_img); + u32 fctl = 0; + u32 rsf = 0; + u32 endianness = 0; + bool yuv_semi_planar = + dst_img->fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR || + dst_img->fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR || + dst_img->fmt == B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR || + dst_img->fmt == B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR || + dst_img->fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE || + dst_img->fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE; + + bool yuv_planar = + dst_img->fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR || + dst_img->fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR || + dst_img->fmt == B2R2_BLT_FMT_YVU420_PACKED_PLANAR || + dst_img->fmt == B2R2_BLT_FMT_YVU422_PACKED_PLANAR || + dst_img->fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR; + + u32 dst_pitch = 0; + struct b2r2_control *cont = req->instance->control; + + if (dst_img->pitch == 0) { + /* Determine pitch based on format and width of the image. */ + dst_pitch = get_pitch(cont, dst_img->fmt, dst_img->width); + } else { + dst_pitch = dst_img->pitch; + } + + b2r2_log_info(cont->dev, "%s ENTRY\n", __func__); + + /* Adjustments that depend on the destination format */ + switch (dst_img->fmt) { + case B2R2_BLT_FMT_32_BIT_ABGR8888: + /* Set up IVMX */ + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + + node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_RGB_TO_BGR; + node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_RGB_TO_BGR; + node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_RGB_TO_BGR; + node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_RGB_TO_BGR; + break; + case B2R2_BLT_FMT_Y_CB_Y_CR: + /* Set up IVMX */ + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + /* + * Setup input VMX to convert YVU to RGB 601 VIDEO + * Chroma components are swapped + * so it is YVU and not YUV. + */ + node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_YVU_TO_RGB_601_VIDEO; + break; + case B2R2_BLT_FMT_CB_Y_CR_Y: + /* Set up IVMX */ + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_YUV_TO_RGB_601_VIDEO; + break; + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + /* + * Set up IVMX. + * For B2R2_BLT_FMT_32_BIT_YUV888 and + * B2R2_BLT_FMT_32_BIT_AYUV8888 + * the color components are laid out in memory as V, U, Y, (A) + * with V at the first byte (due to little endian addressing). + * B2R2 expects them to be as U, Y, V, (A) + * with U at the first byte. + */ + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_BLT_YUV888_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_BLT_YUV888_TO_RGB_601_VIDEO; + + /* + * Re-arrange color components from VUY(A) to (A)YUV + * for input VMX to work on them further. + */ + if (dst_img->fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + dst_img->fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) + endianness = B2R2_TY_ENDIAN_BIG_NOT_LITTLE; + break; + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: { + /* Set up IVMX */ + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + + if (dst_img->fmt == B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR || + dst_img->fmt == + B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR) { + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_YVU_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_YVU_TO_RGB_601_VIDEO; + } else { + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_YUV_TO_RGB_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_YUV_TO_RGB_601_VIDEO; + } + + switch (dst_img->fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + /* + * Chrominance is always half the luminance size + * so chrominance resizer is always active. + */ + fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER | + B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER; + + rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT); + rsf |= (1 << 9) << B2R2_RSF_HSRC_INC_SHIFT; + rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT); + rsf |= (1 << 9) << B2R2_RSF_VSRC_INC_SHIFT; + break; + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + /* + * Chrominance is always half the luminance size + * only in horizontal direction. + */ + fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER; + + rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT); + rsf |= (1 << 9) << B2R2_RSF_HSRC_INC_SHIFT; + rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT); + rsf |= (1 << 10) << B2R2_RSF_VSRC_INC_SHIFT; + break; + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + /* Chrominance is the same size as luminance.*/ + fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER | + B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER; + + rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT); + rsf |= (1 << 10) << B2R2_RSF_HSRC_INC_SHIFT; + rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT); + rsf |= (1 << 10) << B2R2_RSF_VSRC_INC_SHIFT; + break; + default: + break; + } + /* Set the filter control and rescale registers for chroma */ + node->node.GROUP8.B2R2_FCTL |= fctl; + node->node.GROUP9.B2R2_RSF |= rsf; + node->node.GROUP9.B2R2_RZI = + B2R2_RZI_DEFAULT_HNB_REPEAT | + (2 << B2R2_RZI_VNB_REPEAT_SHIFT); + node->node.GROUP0.B2R2_INS |= B2R2_INS_RESCALE2D_ENABLED; + node->node.GROUP0.B2R2_CIC |= + B2R2_CIC_FILTER_CONTROL | B2R2_CIC_RESIZE_CHROMA; + break; + } + default: + break; + } + + /* Set target buffer */ + node->node.GROUP1.B2R2_TBA = out_buf->phys_addr; + node->node.GROUP1.B2R2_TTY = + (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) | + B2R2_GENERIC_WORK_BUF_FMT | + B2R2_TY_ALPHA_RANGE_255 | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + if (yuv_planar) { + /* + * Set up chrominance buffers on source 1 and 2, + * luminance on source 3. + * dst_pitch and physical_address apply to luminance, + * corresponding chrominance values have to be derived. + */ + u32 cb_addr = 0; + u32 cr_addr = 0; + u32 chroma_pitch = 0; + bool swapped_chroma = + dst_img->fmt == B2R2_BLT_FMT_YVU420_PACKED_PLANAR || + dst_img->fmt == B2R2_BLT_FMT_YVU422_PACKED_PLANAR; + enum b2r2_native_fmt dst_native_fmt = + to_native_fmt(cont, dst_img->fmt); + + if (swapped_chroma) + cr_addr = req->dst_resolved.physical_address + + dst_pitch * dst_img->height; + else + cb_addr = req->dst_resolved.physical_address + + dst_pitch * dst_img->height; + + switch (dst_img->fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + chroma_pitch = dst_pitch >> 1; + if (swapped_chroma) + cb_addr = cr_addr + chroma_pitch * + (dst_img->height >> 1); + else + cr_addr = cb_addr + chroma_pitch * + (dst_img->height >> 1); + break; + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + chroma_pitch = dst_pitch >> 1; + if (swapped_chroma) + cb_addr = cr_addr + chroma_pitch * + dst_img->height; + else + cr_addr = cb_addr + chroma_pitch * + dst_img->height; + break; + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + chroma_pitch = dst_pitch; + cr_addr = + cb_addr + chroma_pitch * dst_img->height; + break; + default: + break; + } + + node->node.GROUP3.B2R2_SBA = cr_addr; + node->node.GROUP3.B2R2_STY = + (chroma_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + dst_native_fmt | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + node->node.GROUP4.B2R2_SBA = cb_addr; + node->node.GROUP4.B2R2_STY = node->node.GROUP3.B2R2_STY; + + node->node.GROUP5.B2R2_SBA = req->dst_resolved.physical_address; + node->node.GROUP5.B2R2_STY = + (dst_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + dst_native_fmt | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + node->node.GROUP0.B2R2_INS |= + B2R2_INS_SOURCE_1_FETCH_FROM_MEM | + B2R2_INS_SOURCE_2_FETCH_FROM_MEM | + B2R2_INS_SOURCE_3_FETCH_FROM_MEM; + node->node.GROUP0.B2R2_CIC |= + B2R2_CIC_SOURCE_1 | + B2R2_CIC_SOURCE_2 | + B2R2_CIC_SOURCE_3; + } else if (yuv_semi_planar) { + /* + * Set up chrominance buffer on source 2, luminance on source 3. + * dst_pitch and physical_address apply to luminance, + * corresponding chrominance values have to be derived. + * U and V are interleaved at half the luminance resolution, + * which makes the pitch of the UV plane equal + * to luminance pitch. + */ + u32 chroma_addr = req->dst_resolved.physical_address + + dst_pitch * dst_img->height; + u32 chroma_pitch = dst_pitch; + + enum b2r2_native_fmt dst_native_fmt = + to_native_fmt(cont, dst_img->fmt); + + node->node.GROUP4.B2R2_SBA = chroma_addr; + node->node.GROUP4.B2R2_STY = + (chroma_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + dst_native_fmt | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + node->node.GROUP5.B2R2_SBA = req->dst_resolved.physical_address; + node->node.GROUP5.B2R2_STY = + (dst_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + dst_native_fmt | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + node->node.GROUP0.B2R2_INS |= + B2R2_INS_SOURCE_2_FETCH_FROM_MEM | + B2R2_INS_SOURCE_3_FETCH_FROM_MEM; + node->node.GROUP0.B2R2_CIC |= + B2R2_CIC_SOURCE_2 | B2R2_CIC_SOURCE_3; + } else { + /* single buffer format */ + node->node.GROUP4.B2R2_SBA = req->dst_resolved.physical_address; + node->node.GROUP4.B2R2_STY = + (dst_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + to_native_fmt(cont, dst_img->fmt) | + get_alpha_range(cont, dst_img->fmt) | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM | + endianness; + + node->node.GROUP0.B2R2_INS |= + B2R2_INS_SOURCE_2_FETCH_FROM_MEM; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2; + } + + node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BYPASS_S2_S3; + + b2r2_log_info(cont->dev, "%s DONE\n", __func__); +} + +static void setup_blend_stage(const struct b2r2_blt_request *req, + struct b2r2_node *node, + struct b2r2_work_buf *bg_buf, + struct b2r2_work_buf *fg_buf) +{ + u32 global_alpha = req->user_req.global_alpha; +#ifdef CONFIG_B2R2_DEBUG + struct b2r2_control *cont = req->instance->control; +#endif + + b2r2_log_info(cont->dev, "%s ENTRY\n", __func__); + + node->node.GROUP0.B2R2_ACK = 0; + + if (req->user_req.flags & + (B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND | + B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND)) { + /* Some kind of blending needs to be done. */ + if (req->user_req.flags & B2R2_BLT_FLAG_SRC_IS_NOT_PREMULT) + node->node.GROUP0.B2R2_ACK |= + B2R2_ACK_MODE_BLEND_NOT_PREMULT; + else + node->node.GROUP0.B2R2_ACK |= + B2R2_ACK_MODE_BLEND_PREMULT; + + /* + * global_alpha register accepts 0..128 range, + * global_alpha in the request is 0..255, remap needed. + */ + if (req->user_req.flags & B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND) { + if (global_alpha == 255) + global_alpha = 128; + else + global_alpha >>= 1; + } else { + /* + * Use solid global_alpha + * if global alpha blending is not set. + */ + global_alpha = 128; + } + + node->node.GROUP0.B2R2_ACK |= + global_alpha << (B2R2_ACK_GALPHA_ROPID_SHIFT); + + /* Set background on SRC1 channel */ + node->node.GROUP3.B2R2_SBA = bg_buf->phys_addr; + node->node.GROUP3.B2R2_STY = + (B2R2_GENERIC_WORK_BUF_PITCH << + B2R2_TY_BITMAP_PITCH_SHIFT) | + B2R2_GENERIC_WORK_BUF_FMT | + B2R2_TY_ALPHA_RANGE_255 | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + /* Set foreground on SRC2 channel */ + node->node.GROUP4.B2R2_SBA = fg_buf->phys_addr; + node->node.GROUP4.B2R2_STY = + (B2R2_GENERIC_WORK_BUF_PITCH << + B2R2_TY_BITMAP_PITCH_SHIFT) | + B2R2_GENERIC_WORK_BUF_FMT | + B2R2_TY_ALPHA_RANGE_255 | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + /* Set target buffer */ + node->node.GROUP1.B2R2_TBA = bg_buf->phys_addr; + node->node.GROUP1.B2R2_TTY = + (B2R2_GENERIC_WORK_BUF_PITCH << + B2R2_TY_BITMAP_PITCH_SHIFT) | + B2R2_GENERIC_WORK_BUF_FMT | + B2R2_TY_ALPHA_RANGE_255 | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + node->node.GROUP0.B2R2_INS |= + B2R2_INS_SOURCE_1_FETCH_FROM_MEM | + B2R2_INS_SOURCE_2_FETCH_FROM_MEM; + node->node.GROUP0.B2R2_CIC |= + B2R2_CIC_SOURCE_1 | + B2R2_CIC_SOURCE_2; + } else { + /* + * No blending, foreground goes on SRC2. No global alpha. + * EMACSOC TODO: The blending stage should be skipped altogether + * if no blending is to be done. Probably could go directly from + * transform to writeback. + */ + node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BYPASS_S2_S3; + node->node.GROUP0.B2R2_INS |= + B2R2_INS_SOURCE_2_FETCH_FROM_MEM; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2; + + node->node.GROUP4.B2R2_SBA = fg_buf->phys_addr; + node->node.GROUP4.B2R2_STY = + (B2R2_GENERIC_WORK_BUF_PITCH << + B2R2_TY_BITMAP_PITCH_SHIFT) | + B2R2_GENERIC_WORK_BUF_FMT | + B2R2_TY_ALPHA_RANGE_255 | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + node->node.GROUP1.B2R2_TBA = bg_buf->phys_addr; + node->node.GROUP1.B2R2_TTY = + (B2R2_GENERIC_WORK_BUF_PITCH << + B2R2_TY_BITMAP_PITCH_SHIFT) | + B2R2_GENERIC_WORK_BUF_FMT | + B2R2_TY_ALPHA_RANGE_255 | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + } + + b2r2_log_info(cont->dev, "%s DONE\n", __func__); +} + +static void setup_writeback_stage(const struct b2r2_blt_request *req, + struct b2r2_node *node, + struct b2r2_work_buf *in_buf) +{ + const struct b2r2_blt_img *dst_img = &(req->user_req.dst_img); + const enum b2r2_blt_fmt dst_fmt = dst_img->fmt; + const bool yuv_planar_dst = + dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU420_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU422_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR; + + const bool yuv_semi_planar_dst = + dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE || + dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE; + + const u32 group4_b2r2_sty = + (B2R2_GENERIC_WORK_BUF_PITCH << B2R2_TY_BITMAP_PITCH_SHIFT) | + B2R2_GENERIC_WORK_BUF_FMT | + B2R2_TY_ALPHA_RANGE_255 | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM; + + u32 dst_dither = 0; + u32 dst_pitch = 0; + u32 endianness = 0; + + struct b2r2_control *cont = req->instance->control; + + b2r2_log_info(cont->dev, "%s ENTRY\n", __func__); + + if (dst_img->pitch == 0) { + /* Determine pitch based on format and width of the image. */ + dst_pitch = get_pitch(cont, dst_img->fmt, dst_img->width); + } else + dst_pitch = dst_img->pitch; + + if ((req->user_req.flags & B2R2_BLT_FLAG_DITHER) != 0) + dst_dither = B2R2_TTY_RGB_ROUND_DITHER; + + /* Set target buffer(s) */ + if (yuv_planar_dst) { + /* + * three nodes required to write the output. + * Luma, blue chroma and red chroma. + */ + u32 fctl = 0; + u32 rsf = 0; + const u32 group0_b2r2_ins = + B2R2_INS_SOURCE_2_FETCH_FROM_MEM | + B2R2_INS_RECT_CLIP_ENABLED | + B2R2_INS_IVMX_ENABLED; + const u32 group0_b2r2_cic = + B2R2_CIC_SOURCE_2 | + B2R2_CIC_CLIP_WINDOW | + B2R2_CIC_IVMX; + + u32 cb_addr = 0; + u32 cr_addr = 0; + u32 chroma_pitch = 0; + bool swapped_chroma = + dst_fmt == B2R2_BLT_FMT_YVU420_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU422_PACKED_PLANAR; + enum b2r2_native_fmt dst_native_fmt = + to_native_fmt(cont, dst_img->fmt); + enum b2r2_ty alpha_range = get_alpha_range(cont, dst_img->fmt); + + if (swapped_chroma) + cr_addr = req->dst_resolved.physical_address + + dst_pitch * dst_img->height; + else + cb_addr = req->dst_resolved.physical_address + + dst_pitch * dst_img->height; + + switch (dst_fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + chroma_pitch = dst_pitch >> 1; + if (swapped_chroma) + cb_addr = cr_addr + chroma_pitch * + (dst_img->height >> 1); + else + cr_addr = cb_addr + chroma_pitch * + (dst_img->height >> 1); + /* + * Chrominance is always half the luminance size + * so chrominance resizer is always active. + */ + fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER | + B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER; + + rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT); + rsf |= (2 << 10) << B2R2_RSF_HSRC_INC_SHIFT; + rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT); + rsf |= (2 << 10) << B2R2_RSF_VSRC_INC_SHIFT; + break; + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + chroma_pitch = dst_pitch >> 1; + if (swapped_chroma) + cb_addr = cr_addr + chroma_pitch * + dst_img->height; + else + cr_addr = cb_addr + chroma_pitch * + dst_img->height; + /* + * YUV422 or YVU422 + * Chrominance is always half the luminance size + * only in horizontal direction. + */ + fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER; + + rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT); + rsf |= (2 << 10) << B2R2_RSF_HSRC_INC_SHIFT; + rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT); + rsf |= (1 << 10) << B2R2_RSF_VSRC_INC_SHIFT; + break; + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + chroma_pitch = dst_pitch; + cr_addr = + cb_addr + chroma_pitch * dst_img->height; + /* + * No scaling required since + * chrominance is not subsampled. + */ + default: + break; + } + + /* Luma (Y-component) */ + node->node.GROUP1.B2R2_TBA = req->dst_resolved.physical_address; + node->node.GROUP1.B2R2_TTY = + (dst_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + dst_native_fmt | alpha_range | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM | + dst_dither; + + node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_RGB_TO_YUV_601_VIDEO; + + /* bypass ALU, no blending here. Handled in its own stage. */ + node->node.GROUP0.B2R2_ACK = B2R2_ACK_MODE_BYPASS_S2_S3; + node->node.GROUP0.B2R2_INS = group0_b2r2_ins; + node->node.GROUP0.B2R2_CIC |= group0_b2r2_cic; + + /* Set source buffer on SRC2 channel */ + node->node.GROUP4.B2R2_SBA = in_buf->phys_addr; + node->node.GROUP4.B2R2_STY = group4_b2r2_sty; + + /* Blue chroma (U-component)*/ + node = node->next; + node->node.GROUP1.B2R2_TBA = cb_addr; + node->node.GROUP1.B2R2_TTY = + (chroma_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + dst_native_fmt | alpha_range | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM | + dst_dither | + B2R2_TTY_CHROMA_NOT_LUMA; + + node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_RGB_TO_YUV_601_VIDEO; + + node->node.GROUP0.B2R2_ACK = B2R2_ACK_MODE_BYPASS_S2_S3; + node->node.GROUP0.B2R2_INS = group0_b2r2_ins; + node->node.GROUP0.B2R2_CIC |= group0_b2r2_cic; + if (dst_fmt != B2R2_BLT_FMT_YUV444_PACKED_PLANAR) { + node->node.GROUP0.B2R2_INS |= + B2R2_INS_RESCALE2D_ENABLED; + node->node.GROUP0.B2R2_CIC |= + B2R2_CIC_FILTER_CONTROL | + B2R2_CIC_RESIZE_CHROMA; + /* Set the filter control and rescale registers */ + node->node.GROUP8.B2R2_FCTL = fctl; + node->node.GROUP9.B2R2_RSF = rsf; + node->node.GROUP9.B2R2_RZI = + B2R2_RZI_DEFAULT_HNB_REPEAT | + (2 << B2R2_RZI_VNB_REPEAT_SHIFT); + } + + node->node.GROUP4.B2R2_SBA = in_buf->phys_addr; + node->node.GROUP4.B2R2_STY = group4_b2r2_sty; + + + /* + * Red chroma (V-component) + * The flag B2R2_TTY_CB_NOT_CR actually works + * the other way around, i.e. as if it was + * CR_NOT_CB. + */ + node = node->next; + node->node.GROUP1.B2R2_TBA = cr_addr; + node->node.GROUP1.B2R2_TTY = + (chroma_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + dst_native_fmt | alpha_range | + B2R2_TTY_CB_NOT_CR | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM | + dst_dither | + B2R2_TTY_CHROMA_NOT_LUMA; + + node->node.GROUP15.B2R2_VMX0 = B2R2_VMX0_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = B2R2_VMX1_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = B2R2_VMX2_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = B2R2_VMX3_RGB_TO_YUV_601_VIDEO; + + node->node.GROUP0.B2R2_ACK = B2R2_ACK_MODE_BYPASS_S2_S3; + node->node.GROUP0.B2R2_INS = group0_b2r2_ins; + node->node.GROUP0.B2R2_CIC |= group0_b2r2_cic; + if (dst_fmt != B2R2_BLT_FMT_YUV444_PACKED_PLANAR) { + node->node.GROUP0.B2R2_INS |= + B2R2_INS_RESCALE2D_ENABLED; + node->node.GROUP0.B2R2_CIC |= + B2R2_CIC_FILTER_CONTROL | + B2R2_CIC_RESIZE_CHROMA; + /* Set the filter control and rescale registers */ + node->node.GROUP8.B2R2_FCTL = fctl; + node->node.GROUP9.B2R2_RSF = rsf; + node->node.GROUP9.B2R2_RZI = + B2R2_RZI_DEFAULT_HNB_REPEAT | + (2 << B2R2_RZI_VNB_REPEAT_SHIFT); + } + + node->node.GROUP4.B2R2_SBA = in_buf->phys_addr; + node->node.GROUP4.B2R2_STY = group4_b2r2_sty; + } else if (yuv_semi_planar_dst) { + /* + * two nodes required to write the output. + * One node for luma and one for interleaved chroma + * components. + */ + u32 fctl = 0; + u32 rsf = 0; + const u32 group0_b2r2_ins = + B2R2_INS_SOURCE_2_FETCH_FROM_MEM | + B2R2_INS_RECT_CLIP_ENABLED | + B2R2_INS_IVMX_ENABLED; + const u32 group0_b2r2_cic = + B2R2_CIC_SOURCE_2 | + B2R2_CIC_CLIP_WINDOW | + B2R2_CIC_IVMX; + + u32 chroma_addr = req->dst_resolved.physical_address + + dst_pitch * dst_img->height; + u32 chroma_pitch = dst_pitch; + enum b2r2_native_fmt dst_native_fmt = + to_native_fmt(cont, dst_img->fmt); + enum b2r2_ty alpha_range = get_alpha_range(cont, dst_img->fmt); + + if (dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR || + dst_fmt == + B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE || + dst_fmt == B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR) { + /* + * Chrominance is always half the luminance size + * so chrominance resizer is always active. + */ + fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER | + B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER; + + rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT); + rsf |= (2 << 10) << B2R2_RSF_HSRC_INC_SHIFT; + rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT); + rsf |= (2 << 10) << B2R2_RSF_VSRC_INC_SHIFT; + } else { + /* + * YUV422 + * Chrominance is always half the luminance size + * only in horizontal direction. + */ + fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER; + + rsf &= ~(0xffff << B2R2_RSF_HSRC_INC_SHIFT); + rsf |= (2 << 10) << B2R2_RSF_HSRC_INC_SHIFT; + rsf &= ~(0xffff << B2R2_RSF_VSRC_INC_SHIFT); + rsf |= (1 << 10) << B2R2_RSF_VSRC_INC_SHIFT; + } + + /* Luma (Y-component) */ + node->node.GROUP1.B2R2_TBA = req->dst_resolved.physical_address; + node->node.GROUP1.B2R2_TTY = + (dst_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + dst_native_fmt | alpha_range | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM | + dst_dither; + + if (dst_fmt == B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR) { + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_RGB_TO_YVU_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_RGB_TO_YVU_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_RGB_TO_YVU_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_RGB_TO_YVU_601_VIDEO; + } else { + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_RGB_TO_YUV_601_VIDEO; + } + + /* bypass ALU, no blending here. Handled in its own stage. */ + node->node.GROUP0.B2R2_ACK = B2R2_ACK_MODE_BYPASS_S2_S3; + node->node.GROUP0.B2R2_INS = group0_b2r2_ins; + node->node.GROUP0.B2R2_CIC |= group0_b2r2_cic; + + /* Set source buffer on SRC2 channel */ + node->node.GROUP4.B2R2_SBA = in_buf->phys_addr; + node->node.GROUP4.B2R2_STY = group4_b2r2_sty; + + /* Chroma (UV-components)*/ + node = node->next; + node->node.GROUP1.B2R2_TBA = chroma_addr; + node->node.GROUP1.B2R2_TTY = + (chroma_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + dst_native_fmt | alpha_range | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM | + dst_dither | + B2R2_TTY_CHROMA_NOT_LUMA; + + if (dst_fmt == B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR) { + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_RGB_TO_YVU_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_RGB_TO_YVU_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_RGB_TO_YVU_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_RGB_TO_YVU_601_VIDEO; + } else { + node->node.GROUP15.B2R2_VMX0 = + B2R2_VMX0_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX1 = + B2R2_VMX1_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX2 = + B2R2_VMX2_RGB_TO_YUV_601_VIDEO; + node->node.GROUP15.B2R2_VMX3 = + B2R2_VMX3_RGB_TO_YUV_601_VIDEO; + } + + node->node.GROUP0.B2R2_ACK = B2R2_ACK_MODE_BYPASS_S2_S3; + node->node.GROUP0.B2R2_INS = + group0_b2r2_ins | B2R2_INS_RESCALE2D_ENABLED; + node->node.GROUP0.B2R2_CIC |= group0_b2r2_cic | + B2R2_CIC_FILTER_CONTROL | + B2R2_CIC_RESIZE_CHROMA; + + /* Set the filter control and rescale registers */ + node->node.GROUP8.B2R2_FCTL = fctl; + node->node.GROUP9.B2R2_RSF = rsf; + node->node.GROUP9.B2R2_RZI = + B2R2_RZI_DEFAULT_HNB_REPEAT | + (2 << B2R2_RZI_VNB_REPEAT_SHIFT); + + node->node.GROUP4.B2R2_SBA = in_buf->phys_addr; + node->node.GROUP4.B2R2_STY = group4_b2r2_sty; + } else { + /* single buffer target */ + + /* Set up OVMX */ + switch (dst_fmt) { + case B2R2_BLT_FMT_32_BIT_ABGR8888: + node->node.GROUP0.B2R2_INS |= B2R2_INS_OVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_OVMX; + node->node.GROUP16.B2R2_VMX0 = B2R2_VMX0_RGB_TO_BGR; + node->node.GROUP16.B2R2_VMX1 = B2R2_VMX1_RGB_TO_BGR; + node->node.GROUP16.B2R2_VMX2 = B2R2_VMX2_RGB_TO_BGR; + node->node.GROUP16.B2R2_VMX3 = B2R2_VMX3_RGB_TO_BGR; + break; + case B2R2_BLT_FMT_Y_CB_Y_CR: + node->node.GROUP0.B2R2_INS |= B2R2_INS_OVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_OVMX; + node->node.GROUP16.B2R2_VMX0 = + B2R2_VMX0_RGB_TO_YVU_601_VIDEO; + node->node.GROUP16.B2R2_VMX1 = + B2R2_VMX1_RGB_TO_YVU_601_VIDEO; + node->node.GROUP16.B2R2_VMX2 = + B2R2_VMX2_RGB_TO_YVU_601_VIDEO; + node->node.GROUP16.B2R2_VMX3 = + B2R2_VMX3_RGB_TO_YVU_601_VIDEO; + break; + case B2R2_BLT_FMT_24_BIT_YUV888: /* fall through */ + case B2R2_BLT_FMT_32_BIT_AYUV8888: /* fall through */ + case B2R2_BLT_FMT_24_BIT_VUY888: /* fall through */ + case B2R2_BLT_FMT_32_BIT_VUYA8888: + node->node.GROUP0.B2R2_INS |= B2R2_INS_OVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_OVMX; + node->node.GROUP16.B2R2_VMX0 = + B2R2_VMX0_RGB_TO_BLT_YUV888_601_VIDEO; + node->node.GROUP16.B2R2_VMX1 = + B2R2_VMX1_RGB_TO_BLT_YUV888_601_VIDEO; + node->node.GROUP16.B2R2_VMX2 = + B2R2_VMX2_RGB_TO_BLT_YUV888_601_VIDEO; + node->node.GROUP16.B2R2_VMX3 = + B2R2_VMX3_RGB_TO_BLT_YUV888_601_VIDEO; + + /* + * Re-arrange color components from (A)YUV to VUY(A) + * when bytes are stored in memory. + */ + if (dst_fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + dst_fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) + endianness = B2R2_TY_ENDIAN_BIG_NOT_LITTLE; + break; + default: + break; + } + + node->node.GROUP1.B2R2_TBA = req->dst_resolved.physical_address; + node->node.GROUP1.B2R2_TTY = + (dst_pitch << B2R2_TY_BITMAP_PITCH_SHIFT) | + to_native_fmt(cont, dst_img->fmt) | + get_alpha_range(cont, dst_img->fmt) | + B2R2_TY_HSO_LEFT_TO_RIGHT | + B2R2_TY_VSO_TOP_TO_BOTTOM | + dst_dither | + endianness; + + node->node.GROUP0.B2R2_ACK = B2R2_ACK_MODE_BYPASS_S2_S3; + node->node.GROUP0.B2R2_INS |= + B2R2_INS_SOURCE_2_FETCH_FROM_MEM | + B2R2_INS_RECT_CLIP_ENABLED; + node->node.GROUP0.B2R2_CIC |= + B2R2_CIC_SOURCE_2 | B2R2_CIC_CLIP_WINDOW; + + if (req->user_req.flags & B2R2_BLT_FLAG_SOURCE_COLOR_KEY) { + u32 key_color = 0; + + node->node.GROUP0.B2R2_ACK |= + B2R2_ACK_CKEY_SEL_SRC_AFTER_CLUT | + B2R2_ACK_CKEY_RED_MATCH_IF_BETWEEN | + B2R2_ACK_CKEY_GREEN_MATCH_IF_BETWEEN | + B2R2_ACK_CKEY_BLUE_MATCH_IF_BETWEEN; + node->node.GROUP0.B2R2_INS |= B2R2_INS_CKEY_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_COLOR_KEY; + + key_color = to_RGB888(cont, req->user_req.src_color, + req->user_req.src_img.fmt); + node->node.GROUP12.B2R2_KEY1 = key_color; + node->node.GROUP12.B2R2_KEY2 = key_color; + } + + /* Set source buffer on SRC2 channel */ + node->node.GROUP4.B2R2_SBA = in_buf->phys_addr; + node->node.GROUP4.B2R2_STY = group4_b2r2_sty; + } + /* + * Writeback is the last stage. Terminate the program chain + * to prevent out-of-control B2R2 execution. + */ + node->node.GROUP0.B2R2_NIP = 0; + + b2r2_log_info(cont->dev, "%s DONE\n", __func__); +} + +/* + * Public functions + */ +void b2r2_generic_init(struct b2r2_control *cont) +{ + +} + +void b2r2_generic_exit(struct b2r2_control *cont) +{ + +} + +int b2r2_generic_analyze(const struct b2r2_blt_request *req, + s32 *work_buf_width, + s32 *work_buf_height, + u32 *work_buf_count, + u32 *node_count) +{ + /* + * Need at least 4 nodes, read or fill input, read dst, blend + * and write back the result */ + u32 n_nodes = 4; + /* Need at least 2 bufs, 1 for blend output and 1 for input */ + u32 n_work_bufs = 2; + /* Horizontal and vertical scaling factors in 6.10 fixed point format */ + s32 h_scf = 1 << 10; + s32 v_scf = 1 << 10; + enum b2r2_blt_fmt dst_fmt = 0; + bool is_src_fill = false; + bool yuv_planar_dst; + bool yuv_semi_planar_dst; + struct b2r2_blt_rect src_rect; + struct b2r2_blt_rect dst_rect; + struct b2r2_control *cont = req->instance->control; + + if (req == NULL || work_buf_width == NULL || work_buf_height == NULL || + work_buf_count == NULL || node_count == NULL) { + b2r2_log_warn(cont->dev, "%s: Invalid in or out pointers:\n" + "req=0x%p\n" + "work_buf_width=0x%p work_buf_height=0x%p " + "work_buf_count=0x%p\n" + "node_count=0x%p.\n", + __func__, + req, + work_buf_width, work_buf_height, + work_buf_count, + node_count); + return -EINVAL; + } + + dst_fmt = req->user_req.dst_img.fmt; + + is_src_fill = (req->user_req.flags & + (B2R2_BLT_FLAG_SOURCE_FILL | + B2R2_BLT_FLAG_SOURCE_FILL_RAW)) != 0; + + yuv_planar_dst = + dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU420_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU422_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR; + yuv_semi_planar_dst = + dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE || + dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE; + + *node_count = 0; + *work_buf_width = 0; + *work_buf_height = 0; + *work_buf_count = 0; + + if (req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) { + n_nodes++; + n_work_bufs++; + } + + if ((yuv_planar_dst || yuv_semi_planar_dst) && + (req->user_req.flags & B2R2_BLT_FLAG_SOURCE_FILL_RAW)) { + b2r2_log_warn(cont->dev, + "%s: Invalid combination: source_fill_raw" + " and multi-buffer destination.\n", + __func__); + return -EINVAL; + } + + if ((req->user_req.flags & B2R2_BLT_FLAG_SOURCE_COLOR_KEY) != 0 && + (req->user_req.flags & B2R2_BLT_FLAG_DEST_COLOR_KEY)) { + b2r2_log_warn(cont->dev, + "%s: Invalid combination: source and " + "destination color keying.\n", __func__); + return -EINVAL; + } + + if ((req->user_req.flags & + (B2R2_BLT_FLAG_SOURCE_FILL | + B2R2_BLT_FLAG_SOURCE_FILL_RAW)) && + (req->user_req.flags & + (B2R2_BLT_FLAG_SOURCE_COLOR_KEY | + B2R2_BLT_FLAG_DEST_COLOR_KEY))) { + b2r2_log_warn(cont->dev, "%s: Invalid combination: " + "source_fill and color keying.\n", + __func__); + return -EINVAL; + } + + if ((req->user_req.flags & + (B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND | + B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND)) && + (req->user_req.flags & + (B2R2_BLT_FLAG_DEST_COLOR_KEY | + B2R2_BLT_FLAG_SOURCE_COLOR_KEY))) { + b2r2_log_warn(cont->dev, "%s: Invalid combination: " + "blending and color keying.\n", + __func__); + return -EINVAL; + } + + if ((req->user_req.flags & B2R2_BLT_FLAG_SOURCE_MASK) && + (req->user_req.flags & + (B2R2_BLT_FLAG_DEST_COLOR_KEY | + B2R2_BLT_FLAG_SOURCE_COLOR_KEY))) { + b2r2_log_warn(cont->dev, "%s: Invalid combination: source mask" + "and color keying.\n", + __func__); + return -EINVAL; + } + + if (req->user_req.flags & + (B2R2_BLT_FLAG_DEST_COLOR_KEY | + B2R2_BLT_FLAG_SOURCE_MASK)) { + b2r2_log_warn(cont->dev, "%s: Unsupported: source mask, " + "destination color keying.\n", + __func__); + return -ENOSYS; + } + + if ((req->user_req.flags & B2R2_BLT_FLAG_SOURCE_MASK)) { + enum b2r2_blt_fmt src_fmt = req->user_req.src_img.fmt; + bool yuv_src = + src_fmt == B2R2_BLT_FMT_Y_CB_Y_CR || + src_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR || + src_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR || + src_fmt == B2R2_BLT_FMT_YVU420_PACKED_PLANAR || + src_fmt == B2R2_BLT_FMT_YVU422_PACKED_PLANAR || + src_fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR || + src_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR || + src_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR || + src_fmt == B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR || + src_fmt == B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR || + src_fmt == + B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE || + src_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE; + if (yuv_src || src_fmt == B2R2_BLT_FMT_1_BIT_A1 || + src_fmt == B2R2_BLT_FMT_8_BIT_A8) { + b2r2_log_warn(cont->dev, "%s: Unsupported: source " + "color keying with YUV or pure alpha " + "formats.\n", __func__); + return -ENOSYS; + } + } + + /* Check for invalid dimensions that would hinder scale calculations */ + src_rect = req->user_req.src_rect; + dst_rect = req->user_req.dst_rect; + /* Check for invalid src_rect unless src_fill is enabled */ + if (!is_src_fill && (src_rect.x < 0 || src_rect.y < 0 || + src_rect.x + src_rect.width > req->user_req.src_img.width || + src_rect.y + src_rect.height > req->user_req.src_img.height)) { + b2r2_log_warn(cont->dev, "%s: src_rect outside src_img:\n" + "src(x,y,w,h)=(%d, %d, %d, %d) " + "src_img(w,h)=(%d, %d).\n", + __func__, + src_rect.x, src_rect.y, src_rect.width, src_rect.height, + req->user_req.src_img.width, + req->user_req.src_img.height); + return -EINVAL; + } + + if (!is_src_fill && (src_rect.width <= 0 || src_rect.height <= 0)) { + b2r2_log_warn(cont->dev, "%s: Invalid source dimensions:\n" + "src(w,h)=(%d, %d).\n", + __func__, + src_rect.width, src_rect.height); + return -EINVAL; + } + + if (dst_rect.width <= 0 || dst_rect.height <= 0) { + b2r2_log_warn(cont->dev, "%s: Invalid dest dimensions:\n" + "dst(w,h)=(%d, %d).\n", + __func__, + dst_rect.width, dst_rect.height); + return -EINVAL; + } + + if ((req->user_req.flags & B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) && + req->user_req.clut == NULL) { + b2r2_log_warn(cont->dev, "%s: Invalid request: no table " + "specified for CLUT color correction.\n", + __func__); + return -EINVAL; + } + + /* Check for invalid image params */ + if (!is_src_fill && validate_buf(cont, &(req->user_req.src_img), + &(req->src_resolved))) + return -EINVAL; + + if (validate_buf(cont, &(req->user_req.dst_img), &(req->dst_resolved))) + return -EINVAL; + + if (is_src_fill) { + /* + * Params correct for a source fill operation. + * No need for further checking. + */ + if (yuv_planar_dst) + n_nodes += 2; + else if (yuv_semi_planar_dst) + n_nodes++; + + *work_buf_width = B2R2_GENERIC_WORK_BUF_WIDTH; + *work_buf_height = B2R2_GENERIC_WORK_BUF_HEIGHT; + *work_buf_count = n_work_bufs; + *node_count = n_nodes; + b2r2_log_info(cont->dev, "%s DONE buf_w=%d buf_h=%d " + "buf_count=%d node_count=%d\n", __func__, + *work_buf_width, *work_buf_height, + *work_buf_count, *node_count); + return 0; + } + + /* + * Calculate scaling factors, all transform enum values + * that include rotation have the CCW_ROT_90 bit set. + */ + if (req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) { + h_scf = (src_rect.width << 10) / dst_rect.height; + v_scf = (src_rect.height << 10) / dst_rect.width; + } else { + h_scf = (src_rect.width << 10) / dst_rect.width; + v_scf = (src_rect.height << 10) / dst_rect.height; + } + + /* Check for degenerate/out_of_range scaling factors. */ + if (h_scf <= 0 || v_scf <= 0 || h_scf > 0x7C00 || v_scf > 0x7C00) { + b2r2_log_warn(cont->dev, + "%s: Dimensions result in degenerate or " + "out of range scaling:\n" + "src(w,h)=(%d, %d) " + "dst(w,h)=(%d,%d).\n" + "h_scf=0x%.8x, v_scf=0x%.8x\n", + __func__, + src_rect.width, src_rect.height, + dst_rect.width, dst_rect.height, + h_scf, v_scf); + return -EINVAL; + } + + if (yuv_planar_dst) + n_nodes += 2; + else if (yuv_semi_planar_dst) + n_nodes++; + + *work_buf_width = B2R2_GENERIC_WORK_BUF_WIDTH; + *work_buf_height = B2R2_GENERIC_WORK_BUF_HEIGHT; + *work_buf_count = n_work_bufs; + *node_count = n_nodes; + b2r2_log_info(cont->dev, "%s DONE buf_w=%d buf_h=%d buf_count=%d " + "node_count=%d\n", __func__, *work_buf_width, + *work_buf_height, *work_buf_count, *node_count); + return 0; +} + +/* + * + */ +int b2r2_generic_configure(const struct b2r2_blt_request *req, + struct b2r2_node *first, + struct b2r2_work_buf *tmp_bufs, + u32 buf_count) +{ + struct b2r2_node *node = NULL; + struct b2r2_work_buf *in_buf = NULL; + struct b2r2_work_buf *out_buf = NULL; + struct b2r2_work_buf *empty_buf = NULL; + struct b2r2_control *cont = req->instance->control; + +#ifdef B2R2_GENERIC_DEBUG + u32 needed_bufs = 0; + u32 needed_nodes = 0; + s32 work_buf_width = 0; + s32 work_buf_height = 0; + u32 n_nodes = 0; + int invalid_req = b2r2_generic_analyze(req, &work_buf_width, + &work_buf_height, &needed_bufs, + &needed_nodes); + if (invalid_req < 0) { + b2r2_log_warn(cont->dev, + "%s: Invalid request supplied, ec=%d\n", + __func__, invalid_req); + return -EINVAL; + } + + node = first; + + while (node != NULL) { + n_nodes++; + node = node->next; + } + if (n_nodes < needed_nodes) { + b2r2_log_warn(cont->dev, "%s: Not enough nodes %d < %d.\n", + __func__, n_nodes, needed_nodes); + return -EINVAL; + } + + if (buf_count < needed_bufs) { + b2r2_log_warn(cont->dev, "%s: Not enough buffers %d < %d.\n", + __func__, buf_count, needed_bufs); + return -EINVAL; + } + +#endif + + reset_nodes(cont, first); + node = first; + empty_buf = tmp_bufs; + out_buf = empty_buf; + empty_buf++; + /* Prepare input tile. Color_fill or read from src */ + setup_input_stage(req, node, out_buf); + in_buf = out_buf; + out_buf = empty_buf; + empty_buf++; + node = node->next; + + if ((req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) != 0) { + setup_transform_stage(req, node, out_buf, in_buf); + node = node->next; + in_buf = out_buf; + out_buf = empty_buf++; + } + /* EMACSOC TODO: mask */ + /* + if (req->user_req.flags & B2R2_BLT_FLAG_SOURCE_MASK) { + setup_mask_stage(req, node, out_buf, in_buf); + node = node->next; + in_buf = out_buf; + out_buf = empty_buf++; + } + */ + /* Read the part of destination that will be updated */ + setup_dst_read_stage(req, node, out_buf); + node = node->next; + setup_blend_stage(req, node, out_buf, in_buf); + node = node->next; + in_buf = out_buf; + setup_writeback_stage(req, node, in_buf); + return 0; +} + +void b2r2_generic_set_areas(const struct b2r2_blt_request *req, + struct b2r2_node *first, + struct b2r2_blt_rect *dst_rect_area) +{ + /* + * Nodes come in the following order: <input stage>, [transform], + * [src_mask], <dst_read>, <blend>, <writeback> + */ + struct b2r2_node *node = first; + const struct b2r2_blt_rect *dst_rect = &(req->user_req.dst_rect); + const struct b2r2_blt_rect *src_rect = &(req->user_req.src_rect); + const enum b2r2_blt_fmt src_fmt = req->user_req.src_img.fmt; + bool yuv_multi_buffer_src = + src_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR || + src_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR || + src_fmt == B2R2_BLT_FMT_YVU420_PACKED_PLANAR || + src_fmt == B2R2_BLT_FMT_YVU422_PACKED_PLANAR || + src_fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR || + src_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR || + src_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR || + src_fmt == B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR || + src_fmt == B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR || + src_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE || + src_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE; + const enum b2r2_blt_fmt dst_fmt = req->user_req.dst_img.fmt; + const bool yuv_multi_buffer_dst = + dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU420_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU422_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE || + dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE; + s32 h_scf = 1 << 10; + s32 v_scf = 1 << 10; + s32 src_x = 0; + s32 src_y = 0; + s32 src_w = 0; + s32 src_h = 0; + u32 b2r2_rzi = 0; + s32 clip_top = 0; + s32 clip_left = 0; + s32 clip_bottom = req->user_req.dst_img.height - 1; + s32 clip_right = req->user_req.dst_img.width - 1; + /* Dst coords inside the dst_rect, not the buffer */ + s32 dst_x = dst_rect_area->x; + s32 dst_y = dst_rect_area->y; + struct b2r2_control *cont = req->instance->control; + + b2r2_log_info(cont->dev, "%s ENTRY\n", __func__); + + if (req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) { + h_scf = (src_rect->width << 10) / dst_rect->height; + v_scf = (src_rect->height << 10) / dst_rect->width; + } else { + h_scf = (src_rect->width << 10) / dst_rect->width; + v_scf = (src_rect->height << 10) / dst_rect->height; + } + + if (req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) { + /* + * Normally the inverse transform for 90 degree rotation + * is given by: + * | 0 1| |x| | y| + * | | X | | = | | + * |-1 0| |y| |-x| + * but screen coordinates are flipped in y direction + * (compared to usual Cartesian coordinates), hence the offsets. + */ + src_x = (dst_rect->height - dst_y - dst_rect_area->height) * + h_scf; + src_y = dst_x * v_scf; + src_w = dst_rect_area->height * h_scf; + src_h = dst_rect_area->width * v_scf; + } else { + src_x = dst_x * h_scf; + src_y = dst_y * v_scf; + src_w = dst_rect_area->width * h_scf; + src_h = dst_rect_area->height * v_scf; + } + + b2r2_rzi |= ((src_x & 0x3ff) << B2R2_RZI_HSRC_INIT_SHIFT) | + ((src_y & 0x3ff) << B2R2_RZI_VSRC_INIT_SHIFT); + + /* + * src_w must contain all the pixels that contribute + * to a particular tile. + * ((x + 0x3ff) >> 10) is equivalent to ceiling(x), + * expressed in 6.10 fixed point format. + * Every destination tile, maps to a certain area in the source + * rectangle. The area in source will most likely not be a rectangle + * with exact integer dimensions whenever arbitrary scaling is involved. + * Consider the following example. + * Suppose, that width of the current destination tile maps + * to 1.7 pixels in source, starting at x == 5.4, as calculated + * using the scaling factor. + * This means that while the destination tile is written, + * the source should be read from x == 5.4 up to x == 5.4 + 1.7 == 7.1 + * Consequently, color from 3 pixels (x == 5, 6 and 7) + * needs to be read from source. + * The formula below the comment yields: + * ceil(0.4 + 1.7) == ceil(2.1) == 3 + * (src_x & 0x3ff) is the fractional part of src_x, + * which is expressed in 6.10 fixed point format. + * Thus, width of the source area should be 3 pixels wide, + * starting at x == 5. + * However, the reading should not start at x == 5.0 + * but a bit inside, namely x == 5.4 + * The B2R2_RZI register is used to instruct the HW to do so. + * It contains the fractional part that will be added to + * the first pixel coordinate, before incrementing the current source + * coordinate with the step specified in B2R2_RSF register. + * The same applies to scaling in vertical direction. + */ + src_w = ((src_x & 0x3ff) + src_w + 0x3ff) >> 10; + src_h = ((src_y & 0x3ff) + src_h + 0x3ff) >> 10; + + /* + * EMACSOC TODO: Remove this debug clamp, once tile size + * is taken into account in generic_analyze() + */ + if (src_w > 128) + src_w = 128; + + src_x >>= 10; + src_y >>= 10; + + if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_H) + src_x = src_rect->width - src_x - src_w; + + if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_V) + src_y = src_rect->height - src_y - src_h; + + /* + * Translate the src/dst_rect coordinates into true + * src/dst_buffer coordinates + */ + src_x += src_rect->x; + src_y += src_rect->y; + + dst_x += dst_rect->x; + dst_y += dst_rect->y; + + /* + * Clamp the src coords to buffer dimensions + * to prevent illegal reads. + */ + if (src_x < 0) + src_x = 0; + + if (src_y < 0) + src_y = 0; + + if ((src_x + src_w) > req->user_req.src_img.width) + src_w = req->user_req.src_img.width - src_x; + + if ((src_y + src_h) > req->user_req.src_img.height) + src_h = req->user_req.src_img.height - src_y; + + + /* The input node */ + if (yuv_multi_buffer_src) { + /* Luma on SRC3 */ + node->node.GROUP5.B2R2_SXY = + ((src_x & 0xffff) << B2R2_XY_X_SHIFT) | + ((src_y & 0xffff) << B2R2_XY_Y_SHIFT); + node->node.GROUP5.B2R2_SSZ = + ((src_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) | + ((src_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + + /* Clear and set only the SRC_INIT bits */ + node->node.GROUP10.B2R2_RZI &= + ~((0x3ff << B2R2_RZI_HSRC_INIT_SHIFT) | + (0x3ff << B2R2_RZI_VSRC_INIT_SHIFT)); + node->node.GROUP10.B2R2_RZI |= b2r2_rzi; + + node->node.GROUP9.B2R2_RZI &= + ~((0x3ff << B2R2_RZI_HSRC_INIT_SHIFT) | + (0x3ff << B2R2_RZI_VSRC_INIT_SHIFT)); + switch (src_fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + /* + * Chroma goes on SRC2 and potentially on SRC1. + * Chroma is half the size of luma. Must round up + * the chroma size to handle cases when luma size is not + * divisible by 2. + * E.g. luma width==7 requires chroma width==4. + * Chroma width==7/2==3 is only enough + * for luma width==6. + */ + node->node.GROUP4.B2R2_SXY = + (((src_x & 0xffff) >> 1) << B2R2_XY_X_SHIFT) | + (((src_y & 0xffff) >> 1) << B2R2_XY_Y_SHIFT); + node->node.GROUP4.B2R2_SSZ = + ((((src_w + 1) & 0xfff) >> 1) << + B2R2_SZ_WIDTH_SHIFT) | + ((((src_h + 1) & 0xfff) >> 1) << + B2R2_SZ_HEIGHT_SHIFT); + if (src_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR || + src_fmt == + B2R2_BLT_FMT_YVU420_PACKED_PLANAR) { + node->node.GROUP3.B2R2_SXY = + node->node.GROUP4.B2R2_SXY; + node->node.GROUP3.B2R2_SSZ = + node->node.GROUP4.B2R2_SSZ; + } + node->node.GROUP9.B2R2_RZI |= (b2r2_rzi >> 1) & + ((0x3ff << B2R2_RZI_HSRC_INIT_SHIFT) | + (0x3ff << B2R2_RZI_VSRC_INIT_SHIFT)); + break; + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + /* + * Chroma goes on SRC2 and potentially on SRC1. + * Now chroma is half the size of luma + * only in horizontal direction. + * Same rounding applies as for 420 formats above, + * except it is only done horizontally. + */ + node->node.GROUP4.B2R2_SXY = + (((src_x & 0xffff) >> 1) << B2R2_XY_X_SHIFT) | + ((src_y & 0xffff) << B2R2_XY_Y_SHIFT); + node->node.GROUP4.B2R2_SSZ = + ((((src_w + 1) & 0xfff) >> 1) << + B2R2_SZ_WIDTH_SHIFT) | + ((src_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + if (src_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR || + src_fmt == + B2R2_BLT_FMT_YVU422_PACKED_PLANAR) { + node->node.GROUP3.B2R2_SXY = + node->node.GROUP4.B2R2_SXY; + node->node.GROUP3.B2R2_SSZ = + node->node.GROUP4.B2R2_SSZ; + } + node->node.GROUP9.B2R2_RZI |= + (((src_x & 0x3ff) >> 1) << + B2R2_RZI_HSRC_INIT_SHIFT) | + ((src_y & 0x3ff) << B2R2_RZI_VSRC_INIT_SHIFT); + break; + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + /* + * Chroma goes on SRC2 and SRC1. + * It is the same size as luma. + */ + node->node.GROUP4.B2R2_SXY = + ((src_x & 0xffff) << B2R2_XY_X_SHIFT) | + ((src_y & 0xffff) << B2R2_XY_Y_SHIFT); + node->node.GROUP4.B2R2_SSZ = + ((src_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) | + ((src_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + node->node.GROUP3.B2R2_SXY = node->node.GROUP4.B2R2_SXY; + node->node.GROUP3.B2R2_SSZ = node->node.GROUP4.B2R2_SSZ; + + /* Clear and set only the SRC_INIT bits */ + node->node.GROUP9.B2R2_RZI &= + ~((0x3ff << B2R2_RZI_HSRC_INIT_SHIFT) | + (0x3ff << B2R2_RZI_VSRC_INIT_SHIFT)); + node->node.GROUP9.B2R2_RZI |= b2r2_rzi; + break; + default: + break; + } + } else { + node->node.GROUP4.B2R2_SXY = + ((src_x & 0xffff) << B2R2_XY_X_SHIFT) | + ((src_y & 0xffff) << B2R2_XY_Y_SHIFT); + node->node.GROUP4.B2R2_SSZ = + ((src_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) | + ((src_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + + /* Clear and set only the SRC_INIT bits */ + node->node.GROUP9.B2R2_RZI &= + ~((0x3ff << B2R2_RZI_HSRC_INIT_SHIFT) | + (0x3ff << B2R2_RZI_VSRC_INIT_SHIFT)); + node->node.GROUP9.B2R2_RZI |= b2r2_rzi; + } + + node->node.GROUP1.B2R2_TXY = 0; + if (req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) { + /* + * dst_rect_area coordinates are specified + * after potential rotation. + * Input is read before rotation, hence the width and height + * need to be swapped. + * Horizontal and vertical flips are accomplished with + * suitable scanning order while writing + * to the temporary buffer. + */ + if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_H) { + node->node.GROUP1.B2R2_TXY |= + ((dst_rect_area->height - 1) & 0xffff) << + B2R2_XY_X_SHIFT; + } + + if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_V) { + node->node.GROUP1.B2R2_TXY |= + ((dst_rect_area->width - 1) & 0xffff) << + B2R2_XY_Y_SHIFT; + } + + node->node.GROUP1.B2R2_TSZ = + ((dst_rect_area->height & 0xfff) << + B2R2_SZ_WIDTH_SHIFT) | + ((dst_rect_area->width & 0xfff) << + B2R2_SZ_HEIGHT_SHIFT); + } else { + if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_H) { + node->node.GROUP1.B2R2_TXY |= + ((dst_rect_area->width - 1) & 0xffff) << + B2R2_XY_X_SHIFT; + } + + if (req->user_req.transform & B2R2_BLT_TRANSFORM_FLIP_V) { + node->node.GROUP1.B2R2_TXY |= + ((dst_rect_area->height - 1) & 0xffff) << + B2R2_XY_Y_SHIFT; + } + + node->node.GROUP1.B2R2_TSZ = + ((dst_rect_area->width & 0xfff) << + B2R2_SZ_WIDTH_SHIFT) | + ((dst_rect_area->height & 0xfff) << + B2R2_SZ_HEIGHT_SHIFT); + } + + if (req->user_req.flags & + (B2R2_BLT_FLAG_SOURCE_FILL | B2R2_BLT_FLAG_SOURCE_FILL_RAW)) { + /* + * Scan order for source fill should always be left-to-right + * and top-to-bottom. Fill the input tile from top left. + */ + node->node.GROUP1.B2R2_TXY = 0; + node->node.GROUP4.B2R2_SSZ = node->node.GROUP1.B2R2_TSZ; + } + + if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 && + dst_rect_area->y == 0) { + dump_nodes(cont, node, false); + b2r2_log_debug(cont->dev, "%s Input node done.\n", __func__); + } + + /* Transform */ + if ((req->user_req.transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) != 0) { + /* + * Transform node operates on temporary buffers. + * Content always at top left, but scanning order + * has to be flipped during rotation. + * Width and height need to be considered as well, since + * a tile may not necessarily be filled completely. + * dst_rect_area dimensions are specified + * after potential rotation. + * Input is read before rotation, hence the width and height + * need to be swapped on src. + */ + node = node->next; + + node->node.GROUP4.B2R2_SXY = 0; + node->node.GROUP4.B2R2_SSZ = + ((dst_rect_area->height & 0xfff) << + B2R2_SZ_WIDTH_SHIFT) | + ((dst_rect_area->width & 0xfff) << + B2R2_SZ_HEIGHT_SHIFT); + /* Bottom line written first */ + node->node.GROUP1.B2R2_TXY = + ((dst_rect_area->height - 1) & 0xffff) << + B2R2_XY_Y_SHIFT; + + node->node.GROUP1.B2R2_TSZ = + ((dst_rect_area->width & 0xfff) << + B2R2_SZ_WIDTH_SHIFT) | + ((dst_rect_area->height & 0xfff) << + B2R2_SZ_HEIGHT_SHIFT); + + if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 && + dst_rect_area->y == 0) { + dump_nodes(cont, node, false); + b2r2_log_debug(cont->dev, + "%s Tranform node done.\n", __func__); + } + } + + /* Source mask */ + if (req->user_req.flags & B2R2_BLT_FLAG_SOURCE_MASK) { + node = node->next; + /* + * Same coords for mask as for the input stage. + * Should the mask be transformed together with source? + * EMACSOC TODO: Apply mask before any + * transform/scaling is done. + * Otherwise it will be dst_ not src_mask. + */ + if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 && + dst_rect_area->y == 0) { + dump_nodes(cont, node, false); + b2r2_log_debug(cont->dev, + "%s Source mask node done.\n", __func__); + } + } + + /* dst_read */ + if (yuv_multi_buffer_dst) { + s32 dst_w = dst_rect_area->width; + s32 dst_h = dst_rect_area->height; + bool yuv420_dst = + dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU420_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE; + + bool yuv422_dst = + dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU422_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE; + node = node->next; + /* Luma on SRC3 */ + node->node.GROUP5.B2R2_SXY = + ((dst_x & 0xffff) << B2R2_XY_X_SHIFT) | + ((dst_y & 0xffff) << B2R2_XY_Y_SHIFT); + node->node.GROUP5.B2R2_SSZ = + ((dst_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) | + ((dst_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + + if (yuv420_dst) { + /* + * Chroma goes on SRC2 and potentially on SRC1. + * Chroma is half the size of luma. Must round up + * the chroma size to handle cases when luma size is not + * divisible by 2. + * E.g. luma width==7 requires chroma width==4. + * Chroma width==7/2==3 is only enough + * for luma width==6. + */ + node->node.GROUP4.B2R2_SXY = + (((dst_x & 0xffff) >> 1) << B2R2_XY_X_SHIFT) | + (((dst_y & 0xffff) >> 1) << B2R2_XY_Y_SHIFT); + node->node.GROUP4.B2R2_SSZ = + ((((dst_w + 1) & 0xfff) >> 1) << + B2R2_SZ_WIDTH_SHIFT) | + ((((dst_h + 1) & 0xfff) >> 1) << + B2R2_SZ_HEIGHT_SHIFT); + + if (dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR || + dst_fmt == + B2R2_BLT_FMT_YVU420_PACKED_PLANAR) { + node->node.GROUP3.B2R2_SXY = + node->node.GROUP4.B2R2_SXY; + node->node.GROUP3.B2R2_SSZ = + node->node.GROUP4.B2R2_SSZ; + } + } else if (yuv422_dst) { + /* + * Chroma goes on SRC2 and potentially on SRC1. + * Now chroma is half the size of luma + * only in horizontal direction. + * Same rounding applies as for 420 formats above, + * except it is only done horizontally. + */ + node->node.GROUP4.B2R2_SXY = + (((dst_x & 0xffff) >> 1) << B2R2_XY_X_SHIFT) | + ((dst_y & 0xffff) << B2R2_XY_Y_SHIFT); + node->node.GROUP4.B2R2_SSZ = + ((((dst_w + 1) & 0xfff) >> 1) << + B2R2_SZ_WIDTH_SHIFT) | + ((dst_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + + if (dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR || + dst_fmt == + B2R2_BLT_FMT_YVU422_PACKED_PLANAR) { + node->node.GROUP3.B2R2_SXY = + node->node.GROUP4.B2R2_SXY; + node->node.GROUP3.B2R2_SSZ = + node->node.GROUP4.B2R2_SSZ; + } + } else if (dst_fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR) { + /* + * Chroma goes on SRC2 and SRC1. + * It is the same size as luma. + */ + node->node.GROUP4.B2R2_SXY = node->node.GROUP5.B2R2_SXY; + node->node.GROUP4.B2R2_SSZ = node->node.GROUP5.B2R2_SSZ; + node->node.GROUP3.B2R2_SXY = node->node.GROUP5.B2R2_SXY; + node->node.GROUP3.B2R2_SSZ = node->node.GROUP5.B2R2_SSZ; + } + + node->node.GROUP1.B2R2_TXY = 0; + node->node.GROUP1.B2R2_TSZ = + ((dst_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) | + ((dst_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + } else { + node = node->next; + node->node.GROUP4.B2R2_SXY = + ((dst_x & 0xffff) << B2R2_XY_X_SHIFT) | + ((dst_y & 0xffff) << B2R2_XY_Y_SHIFT); + node->node.GROUP4.B2R2_SSZ = + ((dst_rect_area->width & 0xfff) << + B2R2_SZ_WIDTH_SHIFT) | + ((dst_rect_area->height & 0xfff) << + B2R2_SZ_HEIGHT_SHIFT); + node->node.GROUP1.B2R2_TXY = 0; + node->node.GROUP1.B2R2_TSZ = + ((dst_rect_area->width & 0xfff) << + B2R2_SZ_WIDTH_SHIFT) | + ((dst_rect_area->height & 0xfff) << + B2R2_SZ_HEIGHT_SHIFT); + } + + if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 && + dst_rect_area->y == 0) { + dump_nodes(cont, node, false); + b2r2_log_debug(cont->dev, "%s dst_read node done.\n", __func__); + } + + /* blend */ + node = node->next; + node->node.GROUP3.B2R2_SXY = 0; + node->node.GROUP3.B2R2_SSZ = + ((dst_rect_area->width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) | + ((dst_rect_area->height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + /* contents of the foreground temporary buffer always at top left */ + node->node.GROUP4.B2R2_SXY = 0; + node->node.GROUP4.B2R2_SSZ = + ((dst_rect_area->width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) | + ((dst_rect_area->height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + + node->node.GROUP1.B2R2_TXY = 0; + node->node.GROUP1.B2R2_TSZ = + ((dst_rect_area->width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) | + ((dst_rect_area->height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + + if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 && + dst_rect_area->y == 0) { + dump_nodes(cont, node, false); + b2r2_log_debug(cont->dev, "%s Blend node done.\n", __func__); + } + + /* writeback */ + node = node->next; + if ((req->user_req.flags & B2R2_BLT_FLAG_DESTINATION_CLIP) != 0) { + clip_left = req->user_req.dst_clip_rect.x; + clip_top = req->user_req.dst_clip_rect.y; + clip_right = clip_left + req->user_req.dst_clip_rect.width - 1; + clip_bottom = clip_top + req->user_req.dst_clip_rect.height - 1; + } + /* + * Clamp the dst clip rectangle to buffer dimensions to prevent + * illegal writes. An illegal clip rectangle, e.g. outside the + * buffer will be ignored, resulting in nothing being clipped. + */ + if (clip_left < 0 || req->user_req.dst_img.width <= clip_left) + clip_left = 0; + + if (clip_top < 0 || req->user_req.dst_img.height <= clip_top) + clip_top = 0; + + if (clip_right < 0 || req->user_req.dst_img.width <= clip_right) + clip_right = req->user_req.dst_img.width - 1; + + if (clip_bottom < 0 || req->user_req.dst_img.height <= clip_bottom) + clip_bottom = req->user_req.dst_img.height - 1; + + /* + * Only allow writing inside the clip rect. + * INTNL bit in B2R2_CWO should be zero. + */ + node->node.GROUP6.B2R2_CWO = + ((clip_top & 0x7fff) << B2R2_CWO_Y_SHIFT) | + ((clip_left & 0x7fff) << B2R2_CWO_X_SHIFT); + node->node.GROUP6.B2R2_CWS = + ((clip_bottom & 0x7fff) << B2R2_CWS_Y_SHIFT) | + ((clip_right & 0x7fff) << B2R2_CWS_X_SHIFT); + + if (yuv_multi_buffer_dst) { + const s32 dst_w = dst_rect_area->width; + const s32 dst_h = dst_rect_area->height; + int i = 0; + /* Number of nodes required to write chroma output */ + int n_nodes = 1; + if (dst_fmt == B2R2_BLT_FMT_YUV420_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV422_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU420_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YVU422_PACKED_PLANAR || + dst_fmt == B2R2_BLT_FMT_YUV444_PACKED_PLANAR) + n_nodes = 2; + + node->node.GROUP4.B2R2_SXY = 0; + node->node.GROUP4.B2R2_SSZ = + ((dst_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) | + ((dst_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + + /* Luma (Y-component) */ + node->node.GROUP1.B2R2_TXY = + ((dst_x & 0xffff) << B2R2_XY_X_SHIFT) | + ((dst_y & 0xffff) << B2R2_XY_Y_SHIFT); + node->node.GROUP1.B2R2_TSZ = + ((dst_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) | + ((dst_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + + node->node.GROUP6.B2R2_CWO = + ((clip_top & 0x7fff) << B2R2_CWO_Y_SHIFT) | + ((clip_left & 0x7fff) << B2R2_CWO_X_SHIFT); + node->node.GROUP6.B2R2_CWS = + ((clip_bottom & 0x7fff) << B2R2_CWS_Y_SHIFT) | + ((clip_right & 0x7fff) << B2R2_CWS_X_SHIFT); + + if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 && + dst_rect_area->y == 0) { + dump_nodes(cont, node, false); + b2r2_log_debug(cont->dev, + "%s Writeback luma node done.\n", __func__); + } + + node = node->next; + + /* + * Chroma components. 1 or 2 nodes + * for semi-planar or planar buffer respectively. + */ + for (i = 0; i < n_nodes && node != NULL; ++i) { + + node->node.GROUP4.B2R2_SXY = 0; + node->node.GROUP4.B2R2_SSZ = + ((dst_w & 0xfff) << B2R2_SZ_WIDTH_SHIFT) | + ((dst_h & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + + switch (dst_fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + /* + * Chroma is half the size of luma. + * Must round up the chroma size to handle + * cases when luma size is not divisible by 2. + * E.g. luma_width==7 requires chroma_width==4. + * Chroma_width==7/2==3 is only enough + * for luma_width==6. + */ + node->node.GROUP1.B2R2_TXY = + (((dst_x & 0xffff) >> 1) << + B2R2_XY_X_SHIFT) | + (((dst_y & 0xffff) >> 1) << + B2R2_XY_Y_SHIFT); + node->node.GROUP1.B2R2_TSZ = + ((((dst_w + 1) & 0xfff) >> 1) << + B2R2_SZ_WIDTH_SHIFT) | + ((((dst_h + 1) & 0xfff) >> 1) << + B2R2_SZ_HEIGHT_SHIFT); + break; + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + /* + * Now chroma is half the size of luma only + * in horizontal direction. + * Same rounding applies as + * for 420 formats above, except it is only + * done horizontally. + */ + node->node.GROUP1.B2R2_TXY = + (((dst_x & 0xffff) >> 1) << + B2R2_XY_X_SHIFT) | + ((dst_y & 0xffff) << B2R2_XY_Y_SHIFT); + node->node.GROUP1.B2R2_TSZ = + ((((dst_w + 1) & 0xfff) >> 1) << + B2R2_SZ_WIDTH_SHIFT) | + ((dst_h & 0xfff) << + B2R2_SZ_HEIGHT_SHIFT); + break; + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + /* + * Chroma has the same resolution as luma. + */ + node->node.GROUP1.B2R2_TXY = + ((dst_x & 0xffff) << B2R2_XY_X_SHIFT) | + ((dst_y & 0xffff) << B2R2_XY_Y_SHIFT); + node->node.GROUP1.B2R2_TSZ = + ((dst_w & 0xfff) << + B2R2_SZ_WIDTH_SHIFT) | + ((dst_h & 0xfff) << + B2R2_SZ_HEIGHT_SHIFT); + break; + default: + break; + } + + node->node.GROUP6.B2R2_CWO = + ((clip_top & 0x7fff) << B2R2_CWO_Y_SHIFT) | + ((clip_left & 0x7fff) << B2R2_CWO_X_SHIFT); + node->node.GROUP6.B2R2_CWS = + ((clip_bottom & 0x7fff) << B2R2_CWS_Y_SHIFT) | + ((clip_right & 0x7fff) << B2R2_CWS_X_SHIFT); + + if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 && + dst_rect_area->y == 0) { + dump_nodes(cont, node, false); + b2r2_log_debug(cont->dev, "%s Writeback chroma " + "node %d of %d done.\n", + __func__, i + 1, n_nodes); + } + + node = node->next; + } + } else { + node->node.GROUP4.B2R2_SXY = 0; + node->node.GROUP4.B2R2_SSZ = + ((dst_rect_area->width & 0xfff) << + B2R2_SZ_WIDTH_SHIFT) | + ((dst_rect_area->height & 0xfff) << + B2R2_SZ_HEIGHT_SHIFT); + node->node.GROUP1.B2R2_TXY = + ((dst_x & 0xffff) << B2R2_XY_X_SHIFT) | + ((dst_y & 0xffff) << B2R2_XY_Y_SHIFT); + node->node.GROUP1.B2R2_TSZ = + ((dst_rect_area->width & 0xfff) << + B2R2_SZ_WIDTH_SHIFT) | + ((dst_rect_area->height & 0xfff) << + B2R2_SZ_HEIGHT_SHIFT); + + if (B2R2_GENERIC_DEBUG_AREAS && dst_rect_area->x == 0 && + dst_rect_area->y == 0) { + dump_nodes(cont, node, false); + b2r2_log_debug(cont->dev, "%s Writeback node done.\n", + __func__); + } + } + + b2r2_log_info(cont->dev, "%s DONE\n", __func__); +} diff --git a/drivers/video/b2r2/b2r2_generic.h b/drivers/video/b2r2/b2r2_generic.h new file mode 100644 index 00000000000..3b22f654deb --- /dev/null +++ b/drivers/video/b2r2/b2r2_generic.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 generic. Full coverage of user interface but + * non optimized implementation. For Fallback purposes. + * + * Author: Maciej Socha <maciej.socha@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef _LINUX_VIDEO_B2R2_GENERIC_H +#define _LINUX_VIDEO_B2R2_GENERIC_H + +#include <video/b2r2_blt.h> + +#include "b2r2_internal.h" + +/** + * b2r2_generic_init() + */ +void b2r2_generic_init(struct b2r2_control *cont); + +/** + * b2r2_generic_exit() + */ +void b2r2_generic_exit(struct b2r2_control *cont); + +/** + * b2r2_generic_analyze() + */ +int b2r2_generic_analyze(const struct b2r2_blt_request *req, + s32 *work_buf_width, + s32 *work_buf_height, + u32 *work_buf_count, + u32 *node_count); +/** + * b2r2_generic_configure() + */ +int b2r2_generic_configure(const struct b2r2_blt_request *req, + struct b2r2_node *first, + struct b2r2_work_buf *tmp_bufs, + u32 buf_count); +/** + * b2r2_generic_set_areas() + */ +void b2r2_generic_set_areas(const struct b2r2_blt_request *req, + struct b2r2_node *first, + struct b2r2_blt_rect *dst_rect_area); +#endif diff --git a/drivers/video/b2r2/b2r2_global.h b/drivers/video/b2r2/b2r2_global.h new file mode 100644 index 00000000000..38cf74bb753 --- /dev/null +++ b/drivers/video/b2r2/b2r2_global.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 global definitions + * + * Author: Robert Fekete <robert.fekete@stericsson.com> + * Author: Paul Wannback + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __B2R2_GLOBAL_H +#define __B2R2_GLOBAL_H + +/** Sources involved */ + +struct b2r2_system { + unsigned int B2R2_NIP; + unsigned int B2R2_CIC; + unsigned int B2R2_INS; + unsigned int B2R2_ACK; +}; + +struct b2r2_target { + unsigned int B2R2_TBA; + unsigned int B2R2_TTY; + unsigned int B2R2_TXY; + unsigned int B2R2_TSZ; +}; + +struct b2r2_color_fill { + unsigned int B2R2_S1CF; + unsigned int B2R2_S2CF; +}; + +struct b2r2_src_config { + unsigned int B2R2_SBA; + unsigned int B2R2_STY; + unsigned int B2R2_SXY; + unsigned int B2R2_SSZ; +}; + +struct b2r2_clip { + unsigned int B2R2_CWO; + unsigned int B2R2_CWS; +}; + +struct b2r2_color_key { + unsigned int B2R2_KEY1; + unsigned int B2R2_KEY2; +}; + +struct b2r2_clut { + unsigned int B2R2_CCO; + unsigned int B2R2_CML; +}; + +struct b2r2_rsz_pl_mask { + unsigned int B2R2_FCTL; + unsigned int B2R2_PMK; +}; + +struct b2r2_Cr_luma_rsz { + unsigned int B2R2_RSF; + unsigned int B2R2_RZI; + unsigned int B2R2_HFP; + unsigned int B2R2_VFP; +}; + +struct b2r2_flikr_filter { + unsigned int B2R2_FF0; + unsigned int B2R2_FF1; + unsigned int B2R2_FF2; + unsigned int B2R2_FF3; +}; + +struct b2r2_xyl { + unsigned int B2R2_XYL; + unsigned int B2R2_XYP; +}; + +struct b2r2_sau { + unsigned int B2R2_SAR; + unsigned int B2R2_USR; +}; + +struct b2r2_vm { + unsigned int B2R2_VMX0; + unsigned int B2R2_VMX1; + unsigned int B2R2_VMX2; + unsigned int B2R2_VMX3; +}; + +struct b2r2_link_list { + + struct b2r2_system GROUP0; + struct b2r2_target GROUP1; + struct b2r2_color_fill GROUP2; + struct b2r2_src_config GROUP3; + struct b2r2_src_config GROUP4; + struct b2r2_src_config GROUP5; + struct b2r2_clip GROUP6; + struct b2r2_clut GROUP7; + struct b2r2_rsz_pl_mask GROUP8; + struct b2r2_Cr_luma_rsz GROUP9; + struct b2r2_Cr_luma_rsz GROUP10; + struct b2r2_flikr_filter GROUP11; + struct b2r2_color_key GROUP12; + struct b2r2_xyl GROUP13; + struct b2r2_sau GROUP14; + struct b2r2_vm GROUP15; + struct b2r2_vm GROUP16; + + unsigned int B2R2_RESERVED[2]; +}; + + +#endif /* !defined(__B2R2_GLOBAL_H) */ diff --git a/drivers/video/b2r2/b2r2_hw.h b/drivers/video/b2r2/b2r2_hw.h new file mode 100644 index 00000000000..d492168913a --- /dev/null +++ b/drivers/video/b2r2/b2r2_hw.h @@ -0,0 +1,707 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 hw definitions + * + * Author: Fredrik Allansson <fredrik.allansson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef B2R2_HW_H__ +#define B2R2_HW_H__ + +#include <linux/bitops.h> + +/* Scaling works in strips 128 pixels wide */ +#define B2R2_RESCALE_MAX_WIDTH 128 + +/* Rotation works in strips 16 pixels wide */ +#define B2R2_ROTATE_MAX_WIDTH 16 + +/* B2R2 color formats */ +#define B2R2_COLOR_FORMAT_SHIFT 16 +enum b2r2_native_fmt { + /* RGB formats */ + B2R2_NATIVE_RGB565 = 0x00 << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_RGB888 = 0x01 << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_ARGB8565 = 0x04 << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_ARGB8888 = 0x05 << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_ARGB1555 = 0x06 << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_ARGB4444 = 0x07 << B2R2_COLOR_FORMAT_SHIFT, + + /* YCbCr formats */ + B2R2_NATIVE_YCBCR888 = 0x10 << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_YCBCR422R = 0x12 << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_AYCBCR8888 = 0x15 << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_YCBCR42X_MB = 0x14 << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_YCBCR42X_R2B = 0x16 << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_YCBCR42X_MBN = 0x0e << B2R2_COLOR_FORMAT_SHIFT, + + /* CLUT formats */ + B2R2_NATIVE_CLUT2 = 0x09 << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_CLUT8 = 0x0b << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_ACLUT44 = 0x0c << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_ACLUT88 = 0x0d << B2R2_COLOR_FORMAT_SHIFT, + + /* Misc. formats */ + B2R2_NATIVE_A1 = 0x18 << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_A8 = 0x19 << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_YUV = 0x1e << B2R2_COLOR_FORMAT_SHIFT, + B2R2_NATIVE_BYTE = 0x1f << B2R2_COLOR_FORMAT_SHIFT, +}; + +/* B2R2_CIC register values */ +enum b2r2_cic { + B2R2_CIC_COLOR_FILL = BIT(1),/*0x00000002*/ + B2R2_CIC_SOURCE_1 = BIT(2),/*0x00000004*/ + B2R2_CIC_SOURCE_2 = BIT(3),/*0x00000008*/ + B2R2_CIC_SOURCE_3 = BIT(4),/*0x00000010*/ + B2R2_CIC_CLIP_WINDOW = BIT(5),/*0x00000020*/ + B2R2_CIC_CLUT = BIT(6),/*0x00000040*/ + B2R2_CIC_FILTER_CONTROL = BIT(7),/*0x00000080*/ + B2R2_CIC_RESIZE_CHROMA = BIT(8),/*0x00000100*/ + B2R2_CIC_RESIZE_LUMA = BIT(9),/*0x00000200*/ + B2R2_CIC_FLICKER_COEFF = BIT(10),/*0x00000400*/ + B2R2_CIC_COLOR_KEY = BIT(11),/*0x00000800*/ + B2R2_CIC_XYL = BIT(12),/*0x00001000*/ + B2R2_CIC_SAU = BIT(13),/*0x00002000*/ + B2R2_CIC_IVMX = BIT(14),/*0x00004000*/ + B2R2_CIC_OVMX = BIT(15),/*0x00008000*/ + B2R2_CIC_PACEDOT = BIT(16),/*0x00010000*/ + B2R2_CIC_VC1 = BIT(17)/*0x00020000*/ +}; + +/* B2R2_INS register values */ +#define B2R2_INS_SOURCE_1_SHIFT 0 +#define B2R2_INS_SOURCE_2_SHIFT 3 +#define B2R2_INS_SOURCE_3_SHIFT 5 +#define B2R2_INS_IVMX_SHIFT 6 +#define B2R2_INS_CLUTOP_SHIFT 7 +#define B2R2_INS_RESCALE2D_SHIFT 8 +#define B2R2_INS_FLICK_FILT_SHIFT 9 +#define B2R2_INS_RECT_CLIP_SHIFT 10 +#define B2R2_INS_CKEY_SHIFT 11 +#define B2R2_INS_OVMX_SHIFT 12 +#define B2R2_INS_DEI_SHIFT 13 +#define B2R2_INS_PLANE_MASK_SHIFT 14 +#define B2R2_INS_XYL_SHIFT 15 +#define B2R2_INS_DOT_SHIFT 16 +#define B2R2_INS_VC1R_SHIFT 17 +#define B2R2_INS_ROTATION_SHIFT 18 +#define B2R2_INS_PACE_DOWN_SHIFT 30 +#define B2R2_INS_BLITCOMPIRQ_SHIFT 31 +enum b2r2_ins { + /* Source 1 config */ + B2R2_INS_SOURCE_1_FETCH_FROM_MEM = 0x1 << B2R2_INS_SOURCE_1_SHIFT, + B2R2_INS_SOURCE_1_COLOR_FILL_REGISTER = 0x3 << B2R2_INS_SOURCE_1_SHIFT, + B2R2_INS_SOURCE_1_DIRECT_COPY = 0x4 << B2R2_INS_SOURCE_1_SHIFT, + B2R2_INS_SOURCE_1_DIRECT_FILL = 0x7 << B2R2_INS_SOURCE_1_SHIFT, + + /* Source 2 config */ + B2R2_INS_SOURCE_2_FETCH_FROM_MEM = 0x1 << B2R2_INS_SOURCE_2_SHIFT, + B2R2_INS_SOURCE_2_COLOR_FILL_REGISTER = 0x3 << B2R2_INS_SOURCE_2_SHIFT, + + /* Source 3 config */ + B2R2_INS_SOURCE_3_FETCH_FROM_MEM = 0x1 << B2R2_INS_SOURCE_3_SHIFT, + + /* Other configs */ + B2R2_INS_IVMX_ENABLED = 0x1 << B2R2_INS_IVMX_SHIFT, + B2R2_INS_CLUTOP_ENABLED = 0x1 << B2R2_INS_CLUTOP_SHIFT, + B2R2_INS_RESCALE2D_ENABLED = 0x1 << B2R2_INS_RESCALE2D_SHIFT, + B2R2_INS_FLICK_FILT_ENABLED = 0x1 << B2R2_INS_FLICK_FILT_SHIFT, + B2R2_INS_RECT_CLIP_ENABLED = 0x1 << B2R2_INS_RECT_CLIP_SHIFT, + B2R2_INS_CKEY_ENABLED = 0x1 << B2R2_INS_CKEY_SHIFT, + B2R2_INS_OVMX_ENABLED = 0x1 << B2R2_INS_OVMX_SHIFT, + B2R2_INS_DEI_ENABLED = 0x1 << B2R2_INS_DEI_SHIFT, + B2R2_INS_PLANE_MASK_ENABLED = 0x1 << B2R2_INS_PLANE_MASK_SHIFT, + B2R2_INS_XYL_ENABLED = 0x1 << B2R2_INS_XYL_SHIFT, + B2R2_INS_DOT_ENABLED = 0x1 << B2R2_INS_DOT_SHIFT, + B2R2_INS_VC1R_ENABLED = 0x1 << B2R2_INS_VC1R_SHIFT, + B2R2_INS_ROTATION_ENABLED = 0x1 << B2R2_INS_ROTATION_SHIFT, + B2R2_INS_PACE_DOWN_ENABLED = 0x1 << B2R2_INS_PACE_DOWN_SHIFT, + B2R2_INS_BLITCOMPIRQ_ENABLED = 0x1 << B2R2_INS_BLITCOMPIRQ_SHIFT, + +}; + +/* B2R2_ACK register values */ +#define B2R2_ACK_MODE_SHIFT 0 +#define B2R2_ACK_SWAP_FG_BG_SHIFT 4 +#define B2R2_ACK_GALPHA_ROPID_SHIFT 8 +#define B2R2_ACK_CKEY_BLUE_SHIFT 16 +#define B2R2_ACK_CKEY_GREEN_SHIFT 18 +#define B2R2_ACK_CKEY_RED_SHIFT 20 +#define B2R2_ACK_CKEY_SEL_SHIFT 22 +enum b2r2_ack { + /* ALU operation modes */ + B2R2_ACK_MODE_LOGICAL_OPERATION = 0x1 << B2R2_ACK_MODE_SHIFT, + B2R2_ACK_MODE_BLEND_NOT_PREMULT = 0x2 << B2R2_ACK_MODE_SHIFT, + B2R2_ACK_MODE_BLEND_PREMULT = 0x3 << B2R2_ACK_MODE_SHIFT, + B2R2_ACK_MODE_CLIPMASK_LOGICAL_FIRST_PASS = 0x4 << B2R2_ACK_MODE_SHIFT, + B2R2_ACK_MODE_CLIPMASK_BLEND = 0x5 << B2R2_ACK_MODE_SHIFT, + B2R2_ACK_MODE_BYPASS_S2_S3 = 0x7 << B2R2_ACK_MODE_SHIFT, + B2R2_ACK_MODE_CLIPMASK_LOGICAL_SECOND_PASS = 0x8 << B2R2_ACK_MODE_SHIFT, + B2R2_ACK_MODE_CLIPMASK_XYL_LOGICAL = 0x9 << B2R2_ACK_MODE_SHIFT, + B2R2_ACK_MODE_CLIPMASK_XYL_BLEND_NOT_PREMULT = + 0xa << B2R2_ACK_MODE_SHIFT, + B2R2_ACK_MODE_CLIPMASK_XYL_BLEND_PREMULT = 0xb << B2R2_ACK_MODE_SHIFT, + + /* ALU channel selection */ + B2R2_ACK_SWAP_FG_BG = 0x1 << B2R2_ACK_SWAP_FG_BG_SHIFT, + + /* Global alpha and ROP IDs */ + B2R2_ACK_ROP_CLEAR = 0x0 << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_AND = 0x1 << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_AND_REV = 0x2 << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_COPY = 0x3 << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_AND_INV = 0x4 << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_NOOP = 0x5 << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_XOR = 0x6 << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_OR = 0x7 << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_NOR = 0x8 << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_EQUIV = 0x9 << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_INVERT = 0xa << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_OR_REV = 0xb << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_COPY_INV = 0xc << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_OR_INV = 0xd << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_NAND = 0xe << B2R2_ACK_GALPHA_ROPID_SHIFT, + B2R2_ACK_ROP_SET = 0xf << B2R2_ACK_GALPHA_ROPID_SHIFT, + + /* Color key configuration bits */ + B2R2_ACK_CKEY_BLUE_MATCH_IF_BETWEEN = 0x1 << B2R2_ACK_CKEY_BLUE_SHIFT, + B2R2_ACK_CKEY_BLUE_MATCH_IF_LT_OR_GT = 0x2 << B2R2_ACK_CKEY_BLUE_SHIFT, + B2R2_ACK_CKEY_RED_MATCH_IF_BETWEEN = 0x1 << B2R2_ACK_CKEY_GREEN_SHIFT, + B2R2_ACK_CKEY_RED_MATCH_IF_LT_OR_GT = 0x2 << B2R2_ACK_CKEY_GREEN_SHIFT, + B2R2_ACK_CKEY_GREEN_MATCH_IF_BETWEEN = 0x1 << B2R2_ACK_CKEY_RED_SHIFT, + B2R2_ACK_CKEY_GREEN_MATCH_IF_LT_OR_GT = 0x2 << B2R2_ACK_CKEY_RED_SHIFT, + + /* Color key input selection */ + B2R2_ACK_CKEY_SEL_DEST = 0x0 << B2R2_ACK_CKEY_SEL_SHIFT, + B2R2_ACK_CKEY_SEL_SRC_BEFORE_CLUT = 0x1 << B2R2_ACK_CKEY_SEL_SHIFT, + B2R2_ACK_CKEY_SEL_SRC_AFTER_CLUT = 0x2 << B2R2_ACK_CKEY_SEL_SHIFT, + B2R2_ACK_CKEY_SEL_BLANKING_S2_ALPHA = 0x3 << B2R2_ACK_CKEY_SEL_SHIFT, +}; + +/* Common <S/T>TY defines */ +#define B2R2_TY_BITMAP_PITCH_SHIFT 0 +#define B2R2_TY_COLOR_FORM_SHIFT 16 +#define B2R2_TY_ALPHA_RANGE_SHIFT 21 +#define B2R2_TY_MB_ACCESS_MODE_SHIFT 23 +#define B2R2_TY_HSO_SHIFT 24 +#define B2R2_TY_VSO_SHIFT 25 +#define B2R2_TY_SUBBYTE_SHIFT 28 +#define B2R2_TY_ENDIAN_SHIFT 30 +#define B2R2_TY_SECURE_SHIFT 31 + +/* Dummy enum for generalization of <S/T>TY registers */ +enum b2r2_ty { + /* Alpha range */ + B2R2_TY_ALPHA_RANGE_128 = 0x0 << B2R2_TY_ALPHA_RANGE_SHIFT, + B2R2_TY_ALPHA_RANGE_255 = 0x1 << B2R2_TY_ALPHA_RANGE_SHIFT, + + /* Access mode in macro-block organized frame buffers */ + B2R2_TY_MB_ACCESS_MODE_FRAME = 0x0 << B2R2_TY_MB_ACCESS_MODE_SHIFT, + B2R2_TY_MB_ACCESS_MODE_FIELD = 0x1 << B2R2_TY_MB_ACCESS_MODE_SHIFT, + + /* Horizontal scan order */ + B2R2_TY_HSO_LEFT_TO_RIGHT = 0x0 << B2R2_TY_HSO_SHIFT, + B2R2_TY_HSO_RIGHT_TO_LEFT = 0x1 << B2R2_TY_HSO_SHIFT, + + /* Vertical scan order */ + B2R2_TY_VSO_TOP_TO_BOTTOM = 0x0 << B2R2_TY_VSO_SHIFT, + B2R2_TY_VSO_BOTTOM_TO_TOP = 0x1 << B2R2_TY_VSO_SHIFT, + + /* Pixel ordering for sub-byte formats (position of right-most pixel) */ + B2R2_TY_SUBBYTE_MSB = 0x0 << B2R2_TY_SUBBYTE_SHIFT, + B2R2_TY_SUBBYTE_LSB = 0x1 << B2R2_TY_SUBBYTE_SHIFT, + + /* Bitmap endianess */ + B2R2_TY_ENDIAN_BIG_NOT_LITTLE = 0x1 << B2R2_TY_ENDIAN_SHIFT, + + /* Secureness of the target memory region */ + B2R2_TY_SECURE_UNSECURE = 0x0 << B2R2_TY_SECURE_SHIFT, + B2R2_TY_SECURE_SECURE = 0x1 << B2R2_TY_SECURE_SHIFT, + + /* Dummy to make sure the data type is large enough */ + B2R2_TY_DUMMY = 0xffffffff, +}; + +/* B2R2_TTY register values */ +#define B2R2_TTY_CB_NOT_CR_SHIFT 22 +#define B2R2_TTY_RGB_ROUND_SHIFT 26 +#define B2R2_TTY_CHROMA_NOT_LUMA_SHIFT 27 +enum b2r2_tty { + + /* Chroma component selection */ + B2R2_TTY_CB_NOT_CR = 0x1 << B2R2_TTY_CB_NOT_CR_SHIFT, + + /* RGB rounding mode */ + B2R2_TTY_RGB_ROUND_NORMAL = 0x0 << B2R2_TTY_RGB_ROUND_SHIFT, + B2R2_TTY_RGB_ROUND_DITHER = 0x1 << B2R2_TTY_RGB_ROUND_SHIFT, + + /* Component selection for splitted frame buffer formats */ + B2R2_TTY_CHROMA_NOT_LUMA = 0x1 << B2R2_TTY_CHROMA_NOT_LUMA_SHIFT, +}; + +/* B2R2_S1TY register values */ +#define B2R2_S1TY_A1_SUBST_SHIFT 22 +#define B2R2_S1TY_ROTATION_SHIFT 27 +#define B2R2_S1TY_RGB_EXPANSION_SHIFT 29 +enum b2r2_s1ty { + + /* Alpha bit substitution mode for ARGB1555 */ + B2R2_S1TY_A1_SUBST_KEY_MODE = 0x1 << B2R2_S1TY_A1_SUBST_SHIFT, + + /* Input rectangle rotation (NOT YET IMPLEMENTED) */ + B2R2_S1TY_ENABLE_ROTATION = 0x1 << B2R2_S1TY_ROTATION_SHIFT, + + /* RGB expansion mode */ + B2R2_S1TY_RGB_EXPANSION_MSB_DUP = 0x0 << B2R2_S1TY_RGB_EXPANSION_SHIFT, + B2R2_S1TY_RGB_EXPANSION_LSP_ZERO = 0x1 << B2R2_S1TY_RGB_EXPANSION_SHIFT, +}; + +/* B2R2_S1TY register values */ +#define B2R2_S2TY_A1_SUBST_SHIFT 22 +#define B2R2_S2TY_CHROMA_LEFT_SHIFT 26 +#define B2R2_S2TY_RGB_EXPANSION_SHIFT 29 +enum b2r2_s2ty { + + /* Alpha bit substitution mode for ARGB1555 */ + B2R2_S2TY_A1_SUBST_KEY_MODE = 0x1 << B2R2_S2TY_A1_SUBST_SHIFT, + + /* Chroma left extension */ + B2R2_S2TY_CHROMA_LEFT_EXT_FOLLOWING_PIXEL = 0x0 + << B2R2_S2TY_CHROMA_LEFT_SHIFT, + B2R2_S2TY_CHROMA_LEFT_EXT_AVERAGE = 0x1 << B2R2_S2TY_CHROMA_LEFT_SHIFT, + + /* RGB expansion mode */ + B2R2_S2TY_RGB_EXPANSION_MSB_DUP = 0x0 << B2R2_S2TY_RGB_EXPANSION_SHIFT, + B2R2_S2TY_RGB_EXPANSION_LSP_ZERO = 0x1 << B2R2_S2TY_RGB_EXPANSION_SHIFT, +}; + +/* B2R2_S1TY register values */ +#define B2R2_S3TY_BLANK_ACC_SHIFT 26 +enum b2r2_s3ty { + /* Enables "blank" access on this source (nothing will be fetched from + memory) */ + B2R2_S3TY_ENABLE_BLANK_ACCESS = 0x1 << B2R2_S3TY_BLANK_ACC_SHIFT, +}; + +/* B2R2_<S or T>XY register values */ +#define B2R2_XY_X_SHIFT 0 +#define B2R2_XY_Y_SHIFT 16 + +/* B2R2_<S or T>SZ register values */ +#define B2R2_SZ_WIDTH_SHIFT 0 +#define B2R2_SZ_HEIGHT_SHIFT 16 + +/* Clip window offset (top left coordinates) */ +#define B2R2_CWO_X_SHIFT 0 +#define B2R2_CWO_Y_SHIFT 16 + +/* Clip window stop (bottom right coordinates) */ +#define B2R2_CWS_X_SHIFT 0 +#define B2R2_CWS_Y_SHIFT 16 + +/* Color look-up table */ +enum b2r2_cco { + B2R2_CCO_CLUT_COLOR_CORRECTION = (1 << 16), + B2R2_CCO_CLUT_UPDATE = (1 << 18), + B2R2_CCO_CLUT_ON_S1 = (1 << 15) +}; + +/* Filter control (2D resize control) */ +enum b2r2_fctl { + /* Horizontal 2D filter mode */ + B2R2_FCTL_HF2D_MODE_ENABLE_COLOR_CHANNEL_FILTER = BIT(0), + B2R2_FCTL_HF2D_MODE_ENABLE_ALPHA_CHANNEL_FILTER = BIT(1), + B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER = BIT(2), + + /* Vertical 2D filter mode */ + B2R2_FCTL_VF2D_MODE_ENABLE_COLOR_CHANNEL_FILTER = BIT(4), + B2R2_FCTL_VF2D_MODE_ENABLE_ALPHA_CHANNEL_FILTER = BIT(5), + B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER = BIT(6), + + /* Alpha borders */ + B2R2_FCTL_ENABLE_ALPHA_BORDER_RIGHT = BIT(12), + B2R2_FCTL_ENABLE_ALPHA_BORDER_LEFT = BIT(13), + B2R2_FCTL_ENABLE_ALPHA_BORDER_BOTTOM = BIT(14), + B2R2_FCTL_ENABLE_ALPHA_BORDER_TOP = BIT(15), + + /* Luma path horizontal 2D filter mode */ + B2R2_FCTL_LUMA_HF2D_MODE_ENABLE_FILTER = BIT(24), + B2R2_FCTL_LUMA_HF2D_MODE_ENABLE_RESIZER = BIT(25), + + /* Luma path vertical 2D filter mode */ + B2R2_FCTL_LUMA_VF2D_MODE_ENABLE_FILTER = BIT(28), + B2R2_FCTL_LUMA_VF2D_MODE_ENABLE_RESIZER = BIT(29), +}; + +/* Resize scaling factor */ +#define B2R2_RSF_HSRC_INC_SHIFT 0 +#define B2R2_RSF_VSRC_INC_SHIFT 16 + +/* Resizer initialization */ +#define B2R2_RZI_HSRC_INIT_SHIFT 0 +#define B2R2_RZI_HNB_REPEAT_SHIFT 12 +#define B2R2_RZI_VSRC_INIT_SHIFT 16 +#define B2R2_RZI_VNB_REPEAT_SHIFT 28 + +/* Default values for the resizer */ +#define B2R2_RZI_DEFAULT_HNB_REPEAT (3 << B2R2_RZI_HNB_REPEAT_SHIFT) +#define B2R2_RZI_DEFAULT_VNB_REPEAT (3 << B2R2_RZI_VNB_REPEAT_SHIFT) + + +/* Bus plug configuration registers */ +enum b2r2_plug_opcode_size { + B2R2_PLUG_OPCODE_SIZE_8 = 0x3, + B2R2_PLUG_OPCODE_SIZE_16 = 0x4, + B2R2_PLUG_OPCODE_SIZE_32 = 0x5, + B2R2_PLUG_OPCODE_SIZE_64 = 0x6, +}; + +enum b2r2_plug_chunk_size { + B2R2_PLUG_CHUNK_SIZE_1 = 0x0, + B2R2_PLUG_CHUNK_SIZE_2 = 0x1, + B2R2_PLUG_CHUNK_SIZE_4 = 0x2, + B2R2_PLUG_CHUNK_SIZE_8 = 0x3, + B2R2_PLUG_CHUNK_SIZE_16 = 0x4, + B2R2_PLUG_CHUNK_SIZE_32 = 0x5, + B2R2_PLUG_CHUNK_SIZE_64 = 0x6, + B2R2_PLUG_CHUNK_SIZE_128 = 0x7, +}; + +enum b2r2_plug_message_size { + B2R2_PLUG_MESSAGE_SIZE_1 = 0x0, + B2R2_PLUG_MESSAGE_SIZE_2 = 0x1, + B2R2_PLUG_MESSAGE_SIZE_4 = 0x2, + B2R2_PLUG_MESSAGE_SIZE_8 = 0x3, + B2R2_PLUG_MESSAGE_SIZE_16 = 0x4, + B2R2_PLUG_MESSAGE_SIZE_32 = 0x5, + B2R2_PLUG_MESSAGE_SIZE_64 = 0x6, + B2R2_PLUG_MESSAGE_SIZE_128 = 0x7, +}; + +enum b2r2_plug_page_size { + B2R2_PLUG_PAGE_SIZE_64 = 0x0, + B2R2_PLUG_PAGE_SIZE_128 = 0x1, + B2R2_PLUG_PAGE_SIZE_256 = 0x2, +}; + +/* Default opcode size */ +#if defined(CONFIG_B2R2_OPSIZE_8) +# define B2R2_PLUG_OPCODE_SIZE_DEFAULT B2R2_PLUG_OPCODE_SIZE_8 +#elif defined(CONFIG_B2R2_OPSIZE_16) +# define B2R2_PLUG_OPCODE_SIZE_DEFAULT B2R2_PLUG_OPCODE_SIZE_16 +#elif defined(CONFIG_B2R2_OPSIZE_32) +# define B2R2_PLUG_OPCODE_SIZE_DEFAULT B2R2_PLUG_OPCODE_SIZE_32 +#elif defined(CONFIG_B2R2_OPSIZE_64) +# define B2R2_PLUG_OPCODE_SIZE_DEFAULT B2R2_PLUG_OPCODE_SIZE_64 +#else +# define B2R2_PLUG_OPCODE_SIZE_DEFAULT 0 +#endif + +/* Default chunk size */ +#if defined(CONFIG_B2R2_CHSIZE_1) +# define B2R2_PLUG_CHUNK_SIZE_DEFAULT B2R2_PLUG_CHUNK_SIZE_1 +#elif defined(CONFIG_B2R2_CHSIZE_2) +# define B2R2_PLUG_CHUNK_SIZE_DEFAULT B2R2_PLUG_CHUNK_SIZE_2 +#elif defined(CONFIG_B2R2_CHSIZE_4) +# define B2R2_PLUG_CHUNK_SIZE_DEFAULT B2R2_PLUG_CHUNK_SIZE_4 +#elif defined(CONFIG_B2R2_CHSIZE_8) +# define B2R2_PLUG_CHUNK_SIZE_DEFAULT B2R2_PLUG_CHUNK_SIZE_8 +#elif defined(CONFIG_B2R2_CHSIZE_16) +# define B2R2_PLUG_CHUNK_SIZE_DEFAULT B2R2_PLUG_CHUNK_SIZE_16 +#elif defined(CONFIG_B2R2_CHSIZE_32) +# define B2R2_PLUG_CHUNK_SIZE_DEFAULT B2R2_PLUG_CHUNK_SIZE_32 +#elif defined(CONFIG_B2R2_CHSIZE_64) +# define B2R2_PLUG_CHUNK_SIZE_DEFAULT B2R2_PLUG_CHUNK_SIZE_64 +#elif defined(CONFIG_B2R2_CHSIZE_128) +# define B2R2_PLUG_CHUNK_SIZE_DEFAULT B2R2_PLUG_CHUNK_SIZE_128 +#else +# define B2R2_PLUG_CHUNK_SIZE_DEFAULT 0 +#endif + +/* Default message size */ +#if defined(CONFIG_B2R2_MGSIZE_1) +# define B2R2_PLUG_MESSAGE_SIZE_DEFAULT B2R2_PLUG_MESSAGE_SIZE_1 +#elif defined(CONFIG_B2R2_MGSIZE_2) +# define B2R2_PLUG_MESSAGE_SIZE_DEFAULT B2R2_PLUG_MESSAGE_SIZE_2 +#elif defined(CONFIG_B2R2_MGSIZE_4) +# define B2R2_PLUG_MESSAGE_SIZE_DEFAULT B2R2_PLUG_MESSAGE_SIZE_4 +#elif defined(CONFIG_B2R2_MGSIZE_8) +# define B2R2_PLUG_MESSAGE_SIZE_DEFAULT B2R2_PLUG_MESSAGE_SIZE_8 +#elif defined(CONFIG_B2R2_MGSIZE_16) +# define B2R2_PLUG_MESSAGE_SIZE_DEFAULT B2R2_PLUG_MESSAGE_SIZE_16 +#elif defined(CONFIG_B2R2_MGSIZE_32) +# define B2R2_PLUG_MESSAGE_SIZE_DEFAULT B2R2_PLUG_MESSAGE_SIZE_32 +#elif defined(CONFIG_B2R2_MGSIZE_64) +# define B2R2_PLUG_MESSAGE_SIZE_DEFAULT B2R2_PLUG_MESSAGE_SIZE_64 +#elif defined(CONFIG_B2R2_MGSIZE_128) +# define B2R2_PLUG_MESSAGE_SIZE_DEFAULT B2R2_PLUG_MESSAGE_SIZE_128 +#else +# define B2R2_PLUG_MESSAGE_SIZE_DEFAULT 0 +#endif + +/* Default page size */ +#if defined(CONFIG_B2R2_PGSIZE_64) +# define B2R2_PLUG_PAGE_SIZE_DEFAULT B2R2_PLUG_PAGE_SIZE_64 +#elif defined(CONFIG_B2R2_PGSIZE_128) +# define B2R2_PLUG_PAGE_SIZE_DEFAULT B2R2_PLUG_PAGE_SIZE_128 +#elif defined(CONFIG_B2R2_PGSIZE_256) +# define B2R2_PLUG_PAGE_SIZE_DEFAULT B2R2_PLUG_PAGE_SIZE_256 +#else +# define B2R2_PLUG_PAGE_SIZE_DEFAULT 0 +#endif + +/* VMX register values for RGB to YUV color conversion */ +/* Magic numbers from 27.11 in DB8500_DesignSpecification_v2.5.pdf */ + +/* 601 Video Matrix (standard 601 conversion) */ +#define B2R2_VMX0_RGB_TO_YUV_601_VIDEO 0x107e4beb +#define B2R2_VMX1_RGB_TO_YUV_601_VIDEO 0x0982581d +#define B2R2_VMX2_RGB_TO_YUV_601_VIDEO 0xfa9ea483 +#define B2R2_VMX3_RGB_TO_YUV_601_VIDEO 0x08000080 + +/* 601 Gfx Matrix (full range conversion) */ +#define B2R2_VMX0_RGB_TO_YUV_601_GFX 0x0e1e8bee +#define B2R2_VMX1_RGB_TO_YUV_601_GFX 0x08420419 +#define B2R2_VMX2_RGB_TO_YUV_601_GFX 0xfb5ed471 +#define B2R2_VMX3_RGB_TO_YUV_601_GFX 0x08004080 + +/* 709 Video Matrix (standard 709 conversion) */ +#define B2R2_VMX0_RGB_TO_YUV_709_VIDEO 0x107e27f4 +#define B2R2_VMX1_RGB_TO_YUV_709_VIDEO 0x06e2dc13 +#define B2R2_VMX2_RGB_TO_YUV_709_VIDEO 0xfc5e6c83 +#define B2R2_VMX3_RGB_TO_YUV_709_VIDEO 0x08000080 + +/* 709 Gfx Matrix (standard 709 conversion) */ +#define B2R2_VMX0_RGB_TO_YUV_709_GFX 0x0e3e6bf5 +#define B2R2_VMX1_RGB_TO_YUV_709_GFX 0x05e27410 +#define B2R2_VMX2_RGB_TO_YUV_709_GFX 0xfcdea471 +#define B2R2_VMX3_RGB_TO_YUV_709_GFX 0x08004080 + +/* VMX register values for YUV to RGB color conversion */ + +/* 601 Video Matrix (standard 601 conversion) */ +#define B2R2_VMX0_YUV_TO_RGB_601_VIDEO 0x2c440000 +#define B2R2_VMX1_YUV_TO_RGB_601_VIDEO 0xe9a403aa +#define B2R2_VMX2_YUV_TO_RGB_601_VIDEO 0x0004013f +#define B2R2_VMX3_YUV_TO_RGB_601_VIDEO 0x34f21322 + +/* 601 Gfx Matrix (full range conversion) */ +#define B2R2_VMX0_YUV_TO_RGB_601_GFX 0x3324a800 +#define B2R2_VMX1_YUV_TO_RGB_601_GFX 0xe604ab9c +#define B2R2_VMX2_YUV_TO_RGB_601_GFX 0x0004a957 +#define B2R2_VMX3_YUV_TO_RGB_601_GFX 0x32121eeb + +/* 709 Video Matrix (standard 709 conversion) */ +#define B2R2_VMX0_YUV_TO_RGB_709_VIDEO 0x31440000 +#define B2R2_VMX1_YUV_TO_RGB_709_VIDEO 0xf16403d1 +#define B2R2_VMX2_YUV_TO_RGB_709_VIDEO 0x00040145 +#define B2R2_VMX3_YUV_TO_RGB_709_VIDEO 0x33b14b18 + +/* 709 Gfx Matrix (standard 709 conversion) */ +#define B2R2_VMX0_YUV_TO_RGB_709_GFX 0x3964a800 +#define B2R2_VMX1_YUV_TO_RGB_709_GFX 0xef04abc9 +#define B2R2_VMX2_YUV_TO_RGB_709_GFX 0x0004a95f +#define B2R2_VMX3_YUV_TO_RGB_709_GFX 0x307132df + +/* VMX register values for RGB to BGR conversion */ +#define B2R2_VMX0_RGB_TO_BGR 0x00000100 +#define B2R2_VMX1_RGB_TO_BGR 0x00040000 +#define B2R2_VMX2_RGB_TO_BGR 0x20000000 +#define B2R2_VMX3_RGB_TO_BGR 0x00000000 + +/* VMX register values for BGR to YUV color conversion */ +/* Note: All BGR -> YUV values are calculated by multiplying + * the RGB -> YUV matrices [A], with [S] to form [A]x[S] where + * |0 0 1| + * S = |0 1 0| + * |1 0 0| + * Essentially swapping first and third columns in + * the matrices (VMX0, VMX1 and VMX2 values). + * The offset vector VMX3 remains untouched. + * Put another way, the value of bits 0 through 9 + * is swapped with the value of + * bits 20 through 31 in VMX0, VMX1 and VMX2, + * taking into consideration the compression + * that is used on bits 0 through 9. Bit 0 being LSB. + */ + +/* 601 Video Matrix (standard 601 conversion) */ +#define B2R2_VMX0_BGR_TO_YUV_601_VIDEO 0xfd7e4883 +#define B2R2_VMX1_BGR_TO_YUV_601_VIDEO 0x03a2584c +#define B2R2_VMX2_BGR_TO_YUV_601_VIDEO 0x107ea7d4 +#define B2R2_VMX3_BGR_TO_YUV_601_VIDEO 0x08000080 + +/* 601 Gfx Matrix (full range conversion) */ +#define B2R2_VMX0_BGR_TO_YUV_601_GFX 0xfdde8870 +#define B2R2_VMX1_BGR_TO_YUV_601_GFX 0x03220442 +#define B2R2_VMX2_BGR_TO_YUV_601_GFX 0x0e3ed7da +#define B2R2_VMX3_BGR_TO_YUV_601_GFX 0x08004080 + +/* 709 Video Matrix (standard 709 conversion) */ +#define B2R2_VMX0_BGR_TO_YUV_709_VIDEO 0xfe9e2483 +#define B2R2_VMX1_BGR_TO_YUV_709_VIDEO 0x0262dc37 +#define B2R2_VMX2_BGR_TO_YUV_709_VIDEO 0x107e6fe2 +#define B2R2_VMX3_BGR_TO_YUV_709_VIDEO 0x08000080 + +/* 709 Gfx Matrix (standard 709 conversion) */ +#define B2R2_VMX0_BGR_TO_YUV_709_GFX 0xfebe6871 +#define B2R2_VMX1_BGR_TO_YUV_709_GFX 0x0202742f +#define B2R2_VMX2_BGR_TO_YUV_709_GFX 0x0e3ea7e6 +#define B2R2_VMX3_BGR_TO_YUV_709_GFX 0x08004080 + + +/* VMX register values for YUV to BGR conversion */ +/* Note: All YUV -> BGR values are constructed + * from the YUV -> RGB ones, by swapping + * first and third rows in the matrix + * (VMX0 and VMX2 values). Further, the first and + * third values in the offset vector need to be + * swapped as well, i.e. bits 0 through 9 are swapped + * with bits 20 through 29 in the VMX3 value. + * Bit 0 being LSB. + */ + +/* 601 Video Matrix (standard 601 conversion) */ +#define B2R2_VMX0_YUV_TO_BGR_601_VIDEO 0x0004013f +#define B2R2_VMX1_YUV_TO_BGR_601_VIDEO 0xe9a403aa +#define B2R2_VMX2_YUV_TO_BGR_601_VIDEO 0x2c440000 +#define B2R2_VMX3_YUV_TO_BGR_601_VIDEO 0x3222134f + +/* 601 Gfx Matrix (full range conversion) */ +#define B2R2_VMX0_YUV_TO_BGR_601_GFX 0x0004a957 +#define B2R2_VMX1_YUV_TO_BGR_601_GFX 0xe604ab9c +#define B2R2_VMX2_YUV_TO_BGR_601_GFX 0x3324a800 +#define B2R2_VMX3_YUV_TO_BGR_601_GFX 0x2eb21f21 + +/* 709 Video Matrix (standard 709 conversion) */ +#define B2R2_VMX0_YUV_TO_BGR_709_VIDEO 0x00040145 +#define B2R2_VMX1_YUV_TO_BGR_709_VIDEO 0xf16403d1 +#define B2R2_VMX2_YUV_TO_BGR_709_VIDEO 0x31440000 +#define B2R2_VMX3_YUV_TO_BGR_709_VIDEO 0x31814b3b + +/* 709 Gfx Matrix (standard 709 conversion) */ +#define B2R2_VMX0_YUV_TO_BGR_709_GFX 0x0004a95f +#define B2R2_VMX1_YUV_TO_BGR_709_GFX 0xef04abc9 +#define B2R2_VMX2_YUV_TO_BGR_709_GFX 0x3964a800 +#define B2R2_VMX3_YUV_TO_BGR_709_GFX 0x2df13307 + + +/* VMX register values for YVU to RGB conversion */ + +/* 601 Video Matrix (standard 601 conversion) */ +#define B2R2_VMX0_YVU_TO_RGB_601_VIDEO 0x00040120 +#define B2R2_VMX1_YVU_TO_RGB_601_VIDEO 0xF544034D +#define B2R2_VMX2_YVU_TO_RGB_601_VIDEO 0x37840000 +#define B2R2_VMX3_YVU_TO_RGB_601_VIDEO 0x34f21322 + +/* VMX register values for RGB to YVU conversion */ + +/* 601 Video Matrix (standard 601 conversion) */ +#define B2R2_VMX0_RGB_TO_YVU_601_VIDEO 0xfa9ea483 +#define B2R2_VMX1_RGB_TO_YVU_601_VIDEO 0x0982581d +#define B2R2_VMX2_RGB_TO_YVU_601_VIDEO 0x107e4beb +#define B2R2_VMX3_RGB_TO_YVU_601_VIDEO 0x08000080 + +/* VMX register values for YVU to BGR conversion */ + +/* 601 Video Matrix (standard 601 conversion) */ +#define B2R2_VMX0_YVU_TO_BGR_601_VIDEO 0x37840000 +#define B2R2_VMX1_YVU_TO_BGR_601_VIDEO 0xF544034D +#define B2R2_VMX2_YVU_TO_BGR_601_VIDEO 0x00040120 +#define B2R2_VMX3_YVU_TO_BGR_601_VIDEO 0x3222134F + +/* VMX register values for BGR to YVU conversion */ + +/* 601 Video Matrix (standard 601 conversion) */ +#define B2R2_VMX0_BGR_TO_YVU_601_VIDEO 0x107ea7d4 +#define B2R2_VMX1_BGR_TO_YVU_601_VIDEO 0x03a2584c +#define B2R2_VMX2_BGR_TO_YVU_601_VIDEO 0xfd7e4883 +#define B2R2_VMX3_BGR_TO_YVU_601_VIDEO 0x08000080 + +/* VMX register values for YVU to YUV conversion */ + +/* 601 Video Matrix (standard 601 conversion) */ +/* Internally, the components are in fact stored + * with luma in the middle, i.e. UYV, which is why + * the values are just like for RGB->BGR conversion. + */ +#define B2R2_VMX0_YVU_TO_YUV_601_VIDEO 0x00000100 +#define B2R2_VMX1_YVU_TO_YUV_601_VIDEO 0x00040000 +#define B2R2_VMX2_YVU_TO_YUV_601_VIDEO 0x20000000 +#define B2R2_VMX3_YVU_TO_YUV_601_VIDEO 0x00000000 + +/* VMX register values for RGB to BLT_YUV888 conversion */ + +/* 601 Video Matrix (standard 601 conversion) */ +/* + * BLT_YUV888 has color components laid out in memory as V, U, Y, (Alpha) + * with V at the first byte (due to little endian addressing). + * B2R2 expects them to be as U, Y, V, (A) + * with U at the first byte. + * Note: RGB -> BLT_YUV888 values are calculated by multiplying + * the RGB -> YUV matrix [A], with [S] to form [S]x[A] where + * |0 1 0| + * S = |0 0 1| + * |1 0 0| + * Essentially changing the order of rows in the original + * matrix [A]. + * row1 -> row3 + * row2 -> row1 + * row3 -> row2 + * Values in the offset vector are swapped in the same manner. + */ +#define B2R2_VMX0_RGB_TO_BLT_YUV888_601_VIDEO 0x0982581d +#define B2R2_VMX1_RGB_TO_BLT_YUV888_601_VIDEO 0xfa9ea483 +#define B2R2_VMX2_RGB_TO_BLT_YUV888_601_VIDEO 0x107e4beb +#define B2R2_VMX3_RGB_TO_BLT_YUV888_601_VIDEO 0x00020080 + +/* VMX register values for BLT_YUV888 to RGB conversion */ + +/* + * Note: BLT_YUV888 -> RGB values are calculated by multiplying + * the YUV -> RGB matrix [A], with [S] to form [A]x[S] where + * |0 0 1| + * S = |1 0 0| + * |0 1 0| + * Essentially changing the order of columns in the original + * matrix [A]. + * col1 -> col3 + * col2 -> col1 + * col3 -> col2 + * Values in the offset vector remain unchanged. + */ +#define B2R2_VMX0_BLT_YUV888_TO_RGB_601_VIDEO 0x20000121 +#define B2R2_VMX1_BLT_YUV888_TO_RGB_601_VIDEO 0x201ea74c +#define B2R2_VMX2_BLT_YUV888_TO_RGB_601_VIDEO 0x2006f000 +#define B2R2_VMX3_BLT_YUV888_TO_RGB_601_VIDEO 0x34f21322 + +/* VMX register values for YUV to BLT_YUV888 conversion */ +#define B2R2_VMX0_YUV_TO_BLT_YUV888 0x00040000 +#define B2R2_VMX1_YUV_TO_BLT_YUV888 0x00000100 +#define B2R2_VMX2_YUV_TO_BLT_YUV888 0x20000000 +#define B2R2_VMX3_YUV_TO_BLT_YUV888 0x00000000 + +/* VMX register values for BLT_YUV888 to YUV conversion */ +#define B2R2_VMX0_BLT_YUV888_TO_YUV 0x00000100 +#define B2R2_VMX1_BLT_YUV888_TO_YUV 0x20000000 +#define B2R2_VMX2_BLT_YUV888_TO_YUV 0x00040000 +#define B2R2_VMX3_BLT_YUV888_TO_YUV 0x00000000 + +/* VMX register values for YVU to BLT_YUV888 conversion */ +#define B2R2_VMX0_YVU_TO_BLT_YUV888 0x00040000 +#define B2R2_VMX1_YVU_TO_BLT_YUV888 0x20000000 +#define B2R2_VMX2_YVU_TO_BLT_YUV888 0x00000100 +#define B2R2_VMX3_YVU_TO_BLT_YUV888 0x00000000 + +/* VMX register values for BLT_YUV888 to YVU conversion */ +#define B2R2_VMX0_BLT_YUV888_TO_YVU 0x00040000 +#define B2R2_VMX1_BLT_YUV888_TO_YVU 0x20000000 +#define B2R2_VMX2_BLT_YUV888_TO_YVU 0x00000100 +#define B2R2_VMX3_BLT_YUV888_TO_YVU 0x00000000 + +#endif /* B2R2_HW_H__ */ diff --git a/drivers/video/b2r2/b2r2_input_validation.c b/drivers/video/b2r2/b2r2_input_validation.c new file mode 100644 index 00000000000..ac8b5728847 --- /dev/null +++ b/drivers/video/b2r2/b2r2_input_validation.c @@ -0,0 +1,496 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * + * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> for ST-Ericsson + * + * 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 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "b2r2_internal.h" +#include "b2r2_input_validation.h" +#include "b2r2_debug.h" +#include "b2r2_utils.h" + +#include <video/b2r2_blt.h> +#include <linux/kernel.h> +#include <linux/errno.h> + + +static bool is_valid_format(enum b2r2_blt_fmt fmt); +static bool is_valid_bg_format(enum b2r2_blt_fmt fmt); + +static bool is_valid_pitch_for_fmt(struct b2r2_control *cont, + u32 pitch, s32 width, enum b2r2_blt_fmt fmt); + +static bool is_aligned_width_for_fmt(s32 width, enum b2r2_blt_fmt fmt); +static s32 width_2_complete_width(s32 width, enum b2r2_blt_fmt fmt); +static bool is_complete_width_for_fmt(s32 width, enum b2r2_blt_fmt fmt); +static bool is_valid_height_for_fmt(s32 height, enum b2r2_blt_fmt fmt); + +static bool validate_img(struct b2r2_control *cont, + struct b2r2_blt_img *img); +static bool validate_rect(struct b2r2_control *cont, + struct b2r2_blt_rect *rect); + + +static bool is_valid_format(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_1_BIT_A1: + case B2R2_BLT_FMT_8_BIT_A8: + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_16_BIT_ARGB4444: + case B2R2_BLT_FMT_16_BIT_ARGB1555: + case B2R2_BLT_FMT_16_BIT_RGB565: + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_24_BIT_RGB888: + case B2R2_BLT_FMT_24_BIT_ARGB8565: + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_ARGB8888: + case B2R2_BLT_FMT_32_BIT_ABGR8888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + return true; + + default: + return false; + } +} + +static bool is_valid_bg_format(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + return false; + default: + return true; + } +} + + +static bool is_valid_pitch_for_fmt(struct b2r2_control *cont, + u32 pitch, s32 width, enum b2r2_blt_fmt fmt) +{ + s32 complete_width; + u32 pitch_derived_from_width; + + complete_width = width_2_complete_width(width, fmt); + + pitch_derived_from_width = b2r2_calc_pitch_from_width(cont, + complete_width, fmt); + + if (pitch < pitch_derived_from_width) + return false; + + switch (fmt) { + case B2R2_BLT_FMT_16_BIT_ARGB4444: + case B2R2_BLT_FMT_16_BIT_ARGB1555: + case B2R2_BLT_FMT_16_BIT_RGB565: + if (!b2r2_is_aligned(pitch, 2)) + return false; + + break; + + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + case B2R2_BLT_FMT_24_BIT_RGB888: + case B2R2_BLT_FMT_24_BIT_ARGB8565: + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_ARGB8888: + case B2R2_BLT_FMT_32_BIT_ABGR8888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + if (!b2r2_is_aligned(pitch, 4)) + return false; + + break; + + default: + break; + } + + return true; +} + + +static bool is_aligned_width_for_fmt(s32 width, enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_24_BIT_RGB888: + case B2R2_BLT_FMT_24_BIT_ARGB8565: + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_24_BIT_VUY888: + if (!b2r2_is_aligned(width, 4)) + return false; + + break; + + case B2R2_BLT_FMT_1_BIT_A1: + if (!b2r2_is_aligned(width, 8)) + return false; + + break; + + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + if (!b2r2_is_aligned(width, 2)) + return false; + + break; + + default: + break; + } + + return true; +} + +static s32 width_2_complete_width(s32 width, enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + return b2r2_align_up(width, 2); + + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + return b2r2_align_up(width, 16); + + default: + return width; + } +} + +static bool is_complete_width_for_fmt(s32 width, enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + if (!b2r2_is_aligned(width, 2)) + return false; + + break; + + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + if (!b2r2_is_aligned(width, 16)) + return false; + + break; + + default: + break; + } + + return true; +} + +static bool is_valid_height_for_fmt(s32 height, enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + if (!b2r2_is_aligned(height, 2)) + return false; + + break; + + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + if (!b2r2_is_aligned(height, 16)) + return false; + + break; + + default: + break; + } + + return true; +} + +static bool validate_img(struct b2r2_control *cont, + struct b2r2_blt_img *img) +{ + /* + * So that we always can do width * height * bpp without overflowing a + * 32 bit signed integer. isqrt(s32_max / max_bpp) was used to + * calculate the value. + */ + static const s32 max_img_width_height = 8191; + + s32 img_size; + + if (!is_valid_format(img->fmt)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!is_valid_format(img->fmt)\n"); + return false; + } + + if (img->width < 0 || img->width > max_img_width_height || + img->height < 0 || img->height > max_img_width_height) { + b2r2_log_info(cont->dev, "Validation Error: " + "img->width < 0 || " + "img->width > max_img_width_height || " + "img->height < 0 || " + "img->height > max_img_width_height\n"); + return false; + } + + if (b2r2_is_mb_fmt(img->fmt)) { + if (!is_complete_width_for_fmt(img->width, img->fmt)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!is_complete_width_for_fmt(img->width," + " img->fmt)\n"); + return false; + } + } else { + if (0 == img->pitch && + (!is_aligned_width_for_fmt(img->width, img->fmt) || + !is_complete_width_for_fmt(img->width, img->fmt))) { + b2r2_log_info(cont->dev, + "Validation Error: " + "0 == img->pitch && " + "(!is_aligned_width_for_fmt(img->width," + " img->fmt) || " + "!is_complete_width_for_fmt(img->width," + " img->fmt))\n"); + return false; + } + + if (img->pitch != 0 && + !is_valid_pitch_for_fmt(cont, img->pitch, img->width, + img->fmt)) { + b2r2_log_info(cont->dev, + "Validation Error: " + "img->pitch != 0 && " + "!is_valid_pitch_for_fmt(cont, " + "img->pitch, img->width, img->fmt)\n"); + return false; + } + } + + if (!is_valid_height_for_fmt(img->width, img->fmt)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!is_valid_height_for_fmt(img->width, img->fmt)\n"); + return false; + } + + img_size = b2r2_get_img_size(cont, img); + + /* + * To keep the entire image inside s32 range. + */ + if ((B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET == img->buf.type || + B2R2_BLT_PTR_FD_OFFSET == img->buf.type) && + img->buf.offset > (u32)b2r2_s32_max - (u32)img_size) { + b2r2_log_info(cont->dev, "Validation Error: " + "(B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET == " + "img->buf.type || B2R2_BLT_PTR_FD_OFFSET == " + "img->buf.type) && img->buf.offset > " + "(u32)B2R2_MAX_S32 - (u32)img_size\n"); + return false; + } + + return true; +} + +static bool validate_rect(struct b2r2_control *cont, + struct b2r2_blt_rect *rect) +{ + if (rect->width < 0 || rect->height < 0) { + b2r2_log_info(cont->dev, "Validation Error: " + "rect->width < 0 || rect->height < 0\n"); + return false; + } + + return true; +} + +bool b2r2_validate_user_req(struct b2r2_control *cont, + struct b2r2_blt_req *req) +{ + bool is_src_img_used; + bool is_bg_img_used; + bool is_src_mask_used; + bool is_dst_clip_rect_used; + + if (req->size != sizeof(struct b2r2_blt_req)) { + b2r2_log_err(cont->dev, "Validation Error: " + "req->size != sizeof(struct b2r2_blt_req)\n"); + return false; + } + + is_src_img_used = !(req->flags & B2R2_BLT_FLAG_SOURCE_FILL || + req->flags & B2R2_BLT_FLAG_SOURCE_FILL_RAW); + is_bg_img_used = (req->flags & B2R2_BLT_FLAG_BG_BLEND); + is_src_mask_used = req->flags & B2R2_BLT_FLAG_SOURCE_MASK; + is_dst_clip_rect_used = req->flags & B2R2_BLT_FLAG_DESTINATION_CLIP; + + if (is_src_img_used || is_src_mask_used) { + if (!validate_rect(cont, &req->src_rect)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!validate_rect(cont, &req->src_rect)\n"); + return false; + } + } + + if (!validate_rect(cont, &req->dst_rect)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!validate_rect(cont, &req->dst_rect)\n"); + return false; + } + + if (is_bg_img_used) { + if (!validate_rect(cont, &req->bg_rect)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!validate_rect(cont, &req->bg_rect)\n"); + return false; + } + } + + if (is_dst_clip_rect_used) { + if (!validate_rect(cont, &req->dst_clip_rect)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!validate_rect(cont, &req->dst_clip_rect)\n"); + return false; + } + } + + if (is_src_img_used) { + struct b2r2_blt_rect src_img_bounding_rect; + + if (!validate_img(cont, &req->src_img)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!validate_img(cont, &req->src_img)\n"); + return false; + } + + b2r2_get_img_bounding_rect(&req->src_img, + &src_img_bounding_rect); + if (!b2r2_is_rect_inside_rect(&req->src_rect, + &src_img_bounding_rect)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!b2r2_is_rect_inside_rect(&req->src_rect, " + "&src_img_bounding_rect)\n"); + return false; + } + } + + if (is_bg_img_used) { + struct b2r2_blt_rect bg_img_bounding_rect; + + if (!validate_img(cont, &req->bg_img)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!validate_img(cont, &req->bg_img)\n"); + return false; + } + + if (!is_valid_bg_format(req->bg_img.fmt)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!is_valid_bg_format(req->bg_img->fmt)\n"); + return false; + } + + b2r2_get_img_bounding_rect(&req->bg_img, + &bg_img_bounding_rect); + if (!b2r2_is_rect_inside_rect(&req->bg_rect, + &bg_img_bounding_rect)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!b2r2_is_rect_inside_rect(&req->bg_rect, " + "&bg_img_bounding_rect)\n"); + return false; + } + } + + if (is_src_mask_used) { + struct b2r2_blt_rect src_mask_bounding_rect; + + if (!validate_img(cont, &req->src_mask)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!validate_img(cont, &req->src_mask)\n"); + return false; + } + + b2r2_get_img_bounding_rect(&req->src_mask, + &src_mask_bounding_rect); + if (!b2r2_is_rect_inside_rect(&req->src_rect, + &src_mask_bounding_rect)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!b2r2_is_rect_inside_rect(&req->src_rect, " + "&src_mask_bounding_rect)\n"); + return false; + } + } + + if (!validate_img(cont, &req->dst_img)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!validate_img(cont, &req->dst_img)\n"); + return false; + } + + if (is_bg_img_used) { + if (!b2r2_is_rect_gte_rect(&req->bg_rect, &req->dst_rect)) { + b2r2_log_info(cont->dev, "Validation Error: " + "!b2r2_is_rect_gte_rect(&req->bg_rect, " + "&req->dst_rect)\n"); + return false; + } + } + + return true; +} diff --git a/drivers/video/b2r2/b2r2_input_validation.h b/drivers/video/b2r2/b2r2_input_validation.h new file mode 100644 index 00000000000..d3c6ae1b296 --- /dev/null +++ b/drivers/video/b2r2/b2r2_input_validation.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * + * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> for ST-Ericsson + * + * 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 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LINUX_DRIVERS_VIDEO_B2R2_INPUT_VALIDATION_H_ +#define _LINUX_DRIVERS_VIDEO_B2R2_INPUT_VALIDATION_H_ + +#include <video/b2r2_blt.h> + +#include "b2r2_internal.h" + +bool b2r2_validate_user_req(struct b2r2_control *cont, + struct b2r2_blt_req *req); + +#endif diff --git a/drivers/video/b2r2/b2r2_internal.h b/drivers/video/b2r2/b2r2_internal.h new file mode 100644 index 00000000000..7a46bbda19e --- /dev/null +++ b/drivers/video/b2r2/b2r2_internal.h @@ -0,0 +1,590 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 internal definitions + * + * Author: Robert Fekete <robert.fekete@stericsson.com> + * Author: Paul Wannback + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef _LINUX_DRIVERS_VIDEO_B2R2_INTERNAL_H_ +#define _LINUX_DRIVERS_VIDEO_B2R2_INTERNAL_H_ + +#include <linux/device.h> +#include <linux/miscdevice.h> +#include <video/b2r2_blt.h> + +#include "b2r2_global.h" +#include "b2r2_hw.h" + +/** + * B2R2_MAX_NBR_DEVICES - The maximum number of B2R2s handled + */ +#define B2R2_MAX_NBR_DEVICES 1 + +/* The maximum possible number of temporary buffers needed */ +#define MAX_TMP_BUFS_NEEDED 2 + +/* Size of the color look-up table */ +#define CLUT_SIZE 1024 + +/** + * b2r2_op_type - the type of B2R2 operation to configure + */ +enum b2r2_op_type { + B2R2_DIRECT_COPY, + B2R2_DIRECT_FILL, + B2R2_COPY, + B2R2_FILL, + B2R2_SCALE, + B2R2_ROTATE, + B2R2_SCALE_AND_ROTATE, + B2R2_FLIP, +}; + +/** + * b2r2_fmt_type - the type of buffer for a given format + */ +enum b2r2_fmt_type { + B2R2_FMT_TYPE_RASTER, + B2R2_FMT_TYPE_SEMI_PLANAR, + B2R2_FMT_TYPE_PLANAR, +}; + +/** + * b2r2_fmt_conv - the type of format conversion to do + */ +enum b2r2_fmt_conv { + B2R2_FMT_CONV_NONE, + B2R2_FMT_CONV_RGB_TO_YUV, + B2R2_FMT_CONV_YUV_TO_RGB, + B2R2_FMT_CONV_YUV_TO_YUV, + B2R2_FMT_CONV_RGB_TO_BGR, + B2R2_FMT_CONV_BGR_TO_RGB, + B2R2_FMT_CONV_YUV_TO_BGR, + B2R2_FMT_CONV_BGR_TO_YUV, +}; + +/** + * enum b2r2_core_queue - Indicates the B2R2 queue that the job belongs to + * + * @B2R2_CORE_QUEUE_AQ1: Application queue 1 + * @B2R2_CORE_QUEUE_AQ2: Application queue 2 + * @B2R2_CORE_QUEUE_AQ3: Application queue 3 + * @B2R2_CORE_QUEUE_AQ4: Application queue 4 + * @B2R2_CORE_QUEUE_CQ1: Composition queue 1 + * @B2R2_CORE_QUEUE_CQ2: Composition queue 2 + * @B2R2_CORE_QUEUE_NO_OF: Number of queues + */ +enum b2r2_core_queue { + B2R2_CORE_QUEUE_AQ1 = 0, + B2R2_CORE_QUEUE_AQ2, + B2R2_CORE_QUEUE_AQ3, + B2R2_CORE_QUEUE_AQ4, + B2R2_CORE_QUEUE_CQ1, + B2R2_CORE_QUEUE_CQ2, + B2R2_CORE_QUEUE_NO_OF, +}; + +#define B2R2_NUM_APPLICATIONS_QUEUES 4 + +/** + * enum b2r2_core_job_state - Indicates the current state of the job + * + * @B2R2_CORE_JOB_IDLE: Never queued + * @B2R2_CORE_JOB_QUEUED: In queue but not started yet + * @B2R2_CORE_JOB_RUNNING: Running, executed by B2R2 + * @B2R2_CORE_JOB_DONE: Completed + * @B2R2_CORE_JOB_CANCELED: Canceled + */ +enum b2r2_core_job_state { + B2R2_CORE_JOB_IDLE = 0, + B2R2_CORE_JOB_QUEUED, + B2R2_CORE_JOB_RUNNING, + B2R2_CORE_JOB_DONE, + B2R2_CORE_JOB_CANCELED, +}; + +/** + * b2r2_work_buf - specification for a temporary work buffer + * + * @size - the size of the buffer (set by b2r2_node_split) + * @phys_addr - the physical address of the buffer (set by b2r2_blt_main) + */ +struct b2r2_work_buf { + u32 size; + u32 phys_addr; + void *virt_addr; + u32 mem_handle; +}; + +struct tmp_buf { + struct b2r2_work_buf buf; + bool in_use; +}; + +/** + * struct b2r2_blt_instance - Represents the B2R2 instance (one per open) + * + * @lock: Lock to protect the instance + * + * @report_list: Ready requests that should be reported, + * @report_list_waitq: Wait queue for report list + * @no_of_active_requests: Number of requests added but not reported + * in callback. + * @synching: true if any client is waiting for b2r2_blt_synch(0) + * @synch_done_waitq: Wait queue to handle synching on request_id 0 + * @control: The b2r2 control entity + */ +struct b2r2_blt_instance { + struct mutex lock; + + /* Requests to be reported */ + struct list_head report_list; + wait_queue_head_t report_list_waitq; + + /* Below for synching */ + u32 no_of_active_requests; + bool synching; + wait_queue_head_t synch_done_waitq; + + struct b2r2_control *control; +}; + +/** + * struct b2r2_node - Represents a B2R2 node with reqister values, executed + * by B2R2. Should be allocated non-cached. + * + * @next: Next node + * @physical_address: Physical address to be given to B2R2 + * (physical address of "node" member below) + * @node: The B2R2 node with register settings. This is the data + * that B2R2 will use. + * + */ +struct b2r2_node { + struct b2r2_node *next; + u32 physical_address; + + int src_tmp_index; + int dst_tmp_index; + + int src_index; + + /* B2R2 regs comes here */ + struct b2r2_link_list node; +}; + +/** + * struct b2r2_resolved_buf - Contains calculated information about + * image buffers. + * + * @physical_address: Physical address of the buffer + * @virtual_address: Virtual address of the buffer + * @is_pmem: true if buffer is from pmem + * @hwmem_session: Hwmem session + * @hwmem_alloc: Hwmem alloc + * @filep: File pointer of mapped file (like pmem device, frame buffer device) + * @file_physical_start: Physical address of file start + * @file_virtual_start: Virtual address of file start + * @file_len: File len + * + */ +struct b2r2_resolved_buf { + u32 physical_address; + void *virtual_address; + bool is_pmem; + struct hwmem_alloc *hwmem_alloc; + /* Data for validation below */ + struct file *filep; + u32 file_physical_start; + u32 file_virtual_start; + u32 file_len; +}; + +/** + * b2r2_node_split_buf - information about a source or destination buffer + * + * @addr - the physical base address + * @chroma_addr - the physical address of the chroma plane + * @chroma_cr_addr - the physical address of the Cr chroma plane + * @fmt - the buffer format + * @fmt_type - the buffer format type + * @rect - the rectangle of the buffer to use + * @color - the color value to use is case of a fill operation + * @pitch - the pixmap byte pitch + * @height - the pixmap height + * @alpha_range - the alpha range of the buffer (0-128 or 0-255) + * @hso - the horizontal scan order + * @vso - the vertical scan order + * @endian - the endianess of the buffer + * @plane_selection - the plane to write if buffer is planar or semi-planar + */ +struct b2r2_node_split_buf { + u32 addr; + u32 chroma_addr; + u32 chroma_cr_addr; + + enum b2r2_blt_fmt fmt; + enum b2r2_fmt_type type; + + struct b2r2_blt_rect rect; + struct b2r2_blt_rect win; + + s32 dx; + s32 dy; + + u32 color; + u16 pitch; + u16 width; + u16 height; + + enum b2r2_ty alpha_range; + enum b2r2_ty hso; + enum b2r2_ty vso; + enum b2r2_ty endian; + enum b2r2_tty dither; + + /* Plane selection (used when writing to a multibuffer format) */ + enum b2r2_tty plane_selection; + + /* Chroma plane selection (used when writing planar formats) */ + enum b2r2_tty chroma_selection; + + int tmp_buf_index; +}; + +/** + * b2r2_node_split_job - an instance of a node split job + * + * @type - the type of operation + * @ivmx - the ivmx matrix to use for color conversion + * @blend - determines if blending is enabled + * @clip - determines if destination clipping is enabled + * @swap_fg_bg - determines if FG and BG should be swapped when blending + * @flags - the flags passed in the blt request + * @flag_param - parameter required by certain flags, + * e.g. color for source color keying. + * @transform - the transforms passed in the blt request + * @global_alpha - the global alpha + * @clip_rect - the clipping rectangle to use + * @horiz_rescale - determmines if horizontal rescaling is enabled + * @horiz_sf - the horizontal scale factor + * @vert_rescale - determines if vertical rescale is enabled + * @vert_sf - the vertical scale factor + * @src - the incoming source buffer + * @bg - the incoming background buffer + * @dst - the outgoing destination buffer + * @work_bufs - work buffer specifications + * @tmp_bufs - temporary buffers + * @buf_count - the number of temporary buffers used for the job + * @node_count - the number of nodes used for the job + * @max_buf_size - the maximum size of temporary buffers + * @nbr_rows - the number of tile rows in the blit operation + * @nbr_cols - the number of time columns in the blit operation + */ +struct b2r2_node_split_job { + enum b2r2_op_type type; + + const u32 *ivmx; + + bool blend; + bool clip; + bool rotation; + + bool swap_fg_bg; + + u32 flags; + u32 flag_param; + u32 transform; + u32 global_alpha; + + struct b2r2_blt_rect clip_rect; + + bool h_rescale; + u16 h_rsf; + + bool v_rescale; + u16 v_rsf; + + struct b2r2_node_split_buf src; + struct b2r2_node_split_buf bg; + struct b2r2_node_split_buf dst; + + struct b2r2_work_buf work_bufs[MAX_TMP_BUFS_NEEDED]; + struct b2r2_node_split_buf tmp_bufs[MAX_TMP_BUFS_NEEDED]; + + u32 buf_count; + u32 node_count; + u32 max_buf_size; +}; + +/** + * struct b2r2_core_job - Represents a B2R2 core job + * + * @start_sentinel: Memory overwrite guard + * + * @tag: Client value. Used by b2r2_core_job_find_first_with_tag(). + * @prio: Job priority, from -19 up to 20. Mapped to the + * B2R2 application queues. Filled in by the client. + * @first_node_address: Physical address of the first node. Filled + * in by the client. + * @last_node_address: Physical address of the last node. Filled + * in by the client. + * + * @callback: Function that will be called when the job is done. + * @acquire_resources: Function that allocates the resources needed + * to execute the job (i.e. SRAM alloc). Must not + * sleep if atomic, should fail with negative error code + * if resources not available. + * @release_resources: Function that releases the resources previously + * allocated by acquire_resources (i.e. SRAM alloc). + * @release: Function that will be called when the reference count reaches + * zero. + * + * @job_id: Unique id for this job, assigned by B2R2 core + * @job_state: The current state of the job + * @jiffies: Number of jiffies needed for this request + * + * @list: List entry element for internal list management + * @event: Wait queue event to wait for job done + * @work: Work queue structure, for callback implementation + * + * @queue: The queue that this job shall be submitted to + * @control: B2R2 Queue control + * @pace_control: For composition queue only + * @interrupt_context: Context for interrupt + * @hw_start_time: The point when the b2r2 HW queue is activated for this job + * @nsec_active_in_hw: Time spent on the b2r2 HW queue for this job + * + * @end_sentinel: Memory overwrite guard + */ +struct b2r2_core_job { + u32 start_sentinel; + + /* Data to be filled in by client */ + int tag; + int prio; + u32 first_node_address; + u32 last_node_address; + void (*callback)(struct b2r2_core_job *); + int (*acquire_resources)(struct b2r2_core_job *, + bool atomic); + void (*release_resources)(struct b2r2_core_job *, + bool atomic); + void (*release)(struct b2r2_core_job *); + + /* Output data, do not modify */ + int job_id; + enum b2r2_core_job_state job_state; + unsigned long jiffies; + + /* Data below is internal to b2r2_core, do not modify */ + + /* Reference counting */ + u32 ref_count; + + /* Internal data */ + struct list_head list; + wait_queue_head_t event; + struct work_struct work; + + /* B2R2 HW data */ + enum b2r2_core_queue queue; + u32 control; + u32 pace_control; + u32 interrupt_context; + + /* Timing data */ + u32 hw_start_time; + s32 nsec_active_in_hw; + + u32 end_sentinel; +}; + +/** + * struct b2r2_blt_request - Represents one B2R2 blit request + * + * @instance: Back pointer to the instance structure + * @list: List item to keep track of requests per instance + * @user_req: The request received from userspace + * @job: The administration structure for the B2R2 job, + * consisting of one or more nodes + * @node_split_job: The administration structure for the B2R2 node split job + * @first_node: Pointer to the first B2R2 node + * @request_id: Request id for this job + * @node_split_handle: Handle of the node split + * @src_resolved: Calculated info about the source buffer + * @src_mask_resolved: Calculated info about the source mask buffer + * @bg_resolved: Calculated info about the background buffer + * @dst_resolved: Calculated info about the destination buffer + * @profile: True if the blit shall be profiled, false otherwise + */ +struct b2r2_blt_request { + struct b2r2_blt_instance *instance; + struct list_head list; + struct b2r2_blt_req user_req; + struct b2r2_core_job job; + struct b2r2_node_split_job node_split_job; + struct b2r2_node *first_node; + int request_id; + + /* Resolved buffer addresses */ + struct b2r2_resolved_buf src_resolved; + struct b2r2_resolved_buf src_mask_resolved; + struct b2r2_resolved_buf bg_resolved; + struct b2r2_resolved_buf dst_resolved; + + /* TBD: Info about SRAM usage & needs */ + struct b2r2_work_buf *bufs; + u32 buf_count; + + /* color look-up table */ + void *clut; + u32 clut_phys_addr; + + /* Profiling stuff */ + bool profile; + + s32 nsec_active_in_cpu; + + u32 start_time_nsec; + s32 total_time_nsec; +}; + +/** + * struct b2r2_mem_heap - The memory heap + * + * @start_phys_addr: Physical memory start address + * @start_virt_ptr: Virtual pointer to start + * @size: Memory size + * @align: Alignment + * @blocks: List of all blocks + * @heap_lock: Protection for the heap + * @node_size: Size of each B2R2 node + * @node_heap: Heap for B2R2 node allocations + * @debugfs_root_dir: Debugfs B2R2 mem root dir + * @debugfs_heap_stats: Debugfs B2R2 memory status + * @debugfs_dir_blocks: Debugfs B2R2 free blocks dir + */ +struct b2r2_mem_heap { + dma_addr_t start_phys_addr; + void *start_virt_ptr; + u32 size; + u32 align; + struct list_head blocks; + spinlock_t heap_lock; + u32 node_size; + struct dma_pool *node_heap; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root_dir; + struct dentry *debugfs_heap_stats; + struct dentry *debugfs_dir_blocks; +#endif +}; + +/** + * + * @miscdev: The miscdev presenting b2r2 to the system + * @dev: The device handle of the b2r2 instance + * @id: The id of the b2r2 instance + * @name: The name of the b2r2 instance + * @data: Used to store a reference to b2r2_core + * @tmp_bufs: Temporary buffers needed in the node splitter + * @filters_initialized: Indicating of filters has been + * initialized for this b2r2 instance + * @mem_heap: The b2r2 heap, e.g. used to allocate nodes + * @debugfs_latest_request: Copy of the latest request issued + * @debugfs_root_dir: The debugfs root directory, e.g. /debugfs/b2r2 + * @debugfs_debug_root_dir: The b2r2 debug root directory, + * e.g. /debugfs/b2r2/debug + * @stat_lock: Spin lock protecting the statistics + * @stat_n_jobs_added: Number of jobs added to b2r2_core + * @stat_n_jobs_released: Number of jobs released (job_release called) + * @stat_n_jobs_in_report_list: Number of jobs currently in the report list + * @stat_n_in_blt: Number of client threads currently exec inside b2r2_blt() + * @stat_n_in_blt_synch: Number of client threads currently waiting for synch + * @stat_n_in_blt_add: Number of client threads currenlty adding in b2r2_blt + * @stat_n_in_blt_wait: Number of client threads currently waiting in b2r2_blt + * @stat_n_in_synch_0: Number of client threads currently in b2r2_blt_sync + * waiting for all client jobs to finish + * @stat_n_in_synch_job: Number of client threads currently in b2r2_blt_sync + * waiting specific job to finish + * @stat_n_in_query_cap: Number of clients currently in query cap + * @stat_n_in_open: Number of clients currently in b2r2_blt_open + * @stat_n_in_release: Number of clients currently in b2r2_blt_release + * @last_job_lock: Mutex protecting last_job + * @last_job: The last running job on this b2r2 instance + * @last_job_chars: Temporary buffer used in printing last_job + * @prev_node_count: Node cound of last_job + */ +struct b2r2_control { + struct miscdevice miscdev; + struct device *dev; + int id; + char name[16]; + void *data; + struct tmp_buf tmp_bufs[MAX_TMP_BUFS_NEEDED]; + int filters_initialized; + struct b2r2_mem_heap mem_heap; +#ifdef CONFIG_DEBUG_FS + struct b2r2_blt_request debugfs_latest_request; + struct dentry *debugfs_root_dir; + struct dentry *debugfs_debug_root_dir; +#endif + struct mutex stat_lock; + unsigned long stat_n_jobs_added; + unsigned long stat_n_jobs_released; + unsigned long stat_n_jobs_in_report_list; + unsigned long stat_n_in_blt; + unsigned long stat_n_in_blt_synch; + unsigned long stat_n_in_blt_add; + unsigned long stat_n_in_blt_wait; + unsigned long stat_n_in_synch_0; + unsigned long stat_n_in_synch_job; + unsigned long stat_n_in_query_cap; + unsigned long stat_n_in_open; + unsigned long stat_n_in_release; + struct mutex last_job_lock; + struct b2r2_node *last_job; + char *last_job_chars; + int prev_node_count; +}; + +/* FIXME: The functions below should be removed when we are + switching to the new Robert Lind allocator */ + +/** + * b2r2_blt_alloc_nodes() - Allocate nodes + * + * @node_count: Number of nodes to allocate + * + * Return: + * Returns a pointer to the first node in the node list. + */ +struct b2r2_node *b2r2_blt_alloc_nodes(struct b2r2_control *cont, + int node_count); + +/** + * b2r2_blt_free_nodes() - Release nodes previously allocated via + * b2r2_generate_nodes + * + * @first_node: First node in linked list of nodes + */ +void b2r2_blt_free_nodes(struct b2r2_control *cont, + struct b2r2_node *first_node); + +/** + * b2r2_blt_module_init() - Initialize the B2R2 blt module + */ +int b2r2_blt_module_init(struct b2r2_control *cont); + +/** + * b2r2_blt_module_exit() - Un-initialize the B2R2 blt module + */ +void b2r2_blt_module_exit(struct b2r2_control *cont); + +#endif diff --git a/drivers/video/b2r2/b2r2_kernel_if.c b/drivers/video/b2r2/b2r2_kernel_if.c new file mode 100644 index 00000000000..373311ccca5 --- /dev/null +++ b/drivers/video/b2r2/b2r2_kernel_if.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 kernel interface for beeing a separate module + * + * Author: Robert Fekete <robert.fekete@stericsson.com> + * Author: Paul Wannback + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/poll.h> +#include <linux/device.h> +#include <linux/miscdevice.h> +#include <linux/list.h> +#ifdef CONFIG_ANDROID_PMEM +#include <linux/android_pmem.h> +#endif +#include <linux/fb.h> +#include <linux/sched.h> +#include <asm/uaccess.h> +#include <asm/cacheflush.h> + +EXPORT_SYMBOL(fget_light); +EXPORT_SYMBOL(fput_light); +EXPORT_SYMBOL(flush_cache_range); +EXPORT_SYMBOL(task_sched_runtime); +#ifdef CONFIG_ANDROID_PMEM +EXPORT_SYMBOL(get_pmem_file); +EXPORT_SYMBOL(put_pmem_file); +EXPORT_SYMBOL(flush_pmem_file); +#endif diff --git a/drivers/video/b2r2/b2r2_mem_alloc.c b/drivers/video/b2r2/b2r2_mem_alloc.c new file mode 100644 index 00000000000..e5235d2c97f --- /dev/null +++ b/drivers/video/b2r2/b2r2_mem_alloc.c @@ -0,0 +1,668 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 internal Memory allocator + * + * Author: Robert Lind <robert.lind@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/fs.h> +#include <linux/list.h> +#include <linux/debugfs.h> +#include <linux/uaccess.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +#include <linux/dmapool.h> + +#include "b2r2_internal.h" +#include "b2r2_mem_alloc.h" + +/* Forward declarations */ +static struct b2r2_mem_block *b2r2_mem_block_alloc( + struct b2r2_control *cont, u32 offset, u32 size, bool free); +static void b2r2_mem_block_free(struct b2r2_mem_block *mem_block); +static int b2r2_mem_heap_status(struct b2r2_mem_heap *mem_heap, + struct b2r2_mem_heap_status *mem_heap_status); + +/* Align value down to specified alignment */ +static inline u32 align_down(u32 align, u32 value) +{ + return value & ~(align - 1); +} + +/* Align value up to specified alignment */ +static inline u32 align_up(u32 align, u32 value) +{ + return (value + align - 1) & ~(align - 1); +} + + +#ifdef CONFIG_DEBUG_FS +/* About debugfs: + * debugfs is a mountable debug file system. + * + * Mount like this: + * mkdir /debug + * mount -t debugfs none /debug + * ls /debug/b2r2/mem + * + * ls -al /debug/b2r2/mem/blocks + * cat /debug/b2r2/mem/stats + */ + + +/* Create string containing memory heap status */ +static char *get_b2r2_mem_stats(struct b2r2_mem_heap *mem_heap, char *buf) +{ + struct b2r2_mem_heap_status mem_heap_status; + + if (b2r2_mem_heap_status(mem_heap, &mem_heap_status) != 0) { + strcpy(buf, "Error, failed to get status\n"); + return buf; + } + + sprintf(buf, + "Handle : 0x%lX\n" + "Physical start address : 0x%lX\n" + "Size : %lu\n" + "Align : %lu\n" + "No of blocks allocated : %lu\n" + "Allocated size : %lu\n" + "No of free blocks : %lu\n" + "Free size : %lu\n" + "No of locks : %lu\n" + "No of locked : %lu\n" + "No of nodes : %lu\n", + (unsigned long) mem_heap, + (unsigned long) mem_heap_status.start_phys_addr, + (unsigned long) mem_heap_status.size, + (unsigned long) mem_heap_status.align, + (unsigned long) mem_heap_status.num_alloc, + (unsigned long) mem_heap_status.allocated_size, + (unsigned long) mem_heap_status.num_free, + (unsigned long) mem_heap_status.free_size, + (unsigned long) mem_heap_status.num_locks, + (unsigned long) mem_heap_status.num_locked, + (unsigned long) mem_heap_status.num_nodes); + + return buf; +} + +/* + * Print memory heap status on file + * (Use like "cat /debug/b2r2/mem/stats") + */ +static int debugfs_b2r2_mem_stats_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + struct b2r2_mem_heap *mem_heap = filp->f_dentry->d_inode->i_private; + char Buf[400]; + size_t dev_size; + int ret = 0; + + get_b2r2_mem_stats(mem_heap, Buf); + dev_size = strlen(Buf); + + /* No more to read if offset != 0 */ + if (*f_pos > dev_size) + goto out; + + if (*f_pos + count > dev_size) + count = dev_size - *f_pos; + + if (copy_to_user(buf, Buf, count)) + ret = -EINVAL; + *f_pos += count; + ret = count; + +out: + return ret; +} + +/* debugfs file operations for the "stats" file */ +static const struct file_operations debugfs_b2r2_mem_stats_fops = { + .owner = THIS_MODULE, + .read = debugfs_b2r2_mem_stats_read, +}; + +/* read function for file in the "blocks" sub directory */ +static int debugfs_b2r2_mem_block_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + struct b2r2_mem_block *mem_block = filp->f_dentry->d_inode->i_private; + char Buf[200]; + size_t dev_size; + int ret = 0; + + dev_size = sprintf(Buf, "offset: %08lX %s size: %8d " + "lock_count: %2d\n", + (unsigned long) mem_block->offset, + mem_block->free ? "free" : "allc", + mem_block->size, + mem_block->lock_count); + + /* No more to read if offset != 0 */ + if (*f_pos > dev_size) + goto out; + + if (*f_pos + count > dev_size) + count = dev_size - *f_pos; + + if (copy_to_user(buf, Buf, count)) + ret = -EINVAL; + *f_pos += count; + ret = count; + +out: + return ret; +} + +/* debugfs file operations for files in the "blocks" directory */ +static const struct file_operations debugfs_b2r2_mem_block_fops = { + .owner = THIS_MODULE, + .read = debugfs_b2r2_mem_block_read, +}; + +/* + * Create or update the debugfs directory entry for a file in the + * "blocks" directory (a memory allocation) + */ +void debugfs_create_mem_block_entry(struct b2r2_mem_block *mem_block, + struct dentry *parent) +{ + struct timespec tm = current_kernel_time(); + struct timespec atime = tm; + struct timespec mtime = tm; + struct timespec ctime = tm; + + if (mem_block->debugfs_block) { + atime = mem_block->debugfs_block->d_inode->i_atime; + ctime = mem_block->debugfs_block->d_inode->i_ctime; + debugfs_remove(mem_block->debugfs_block); + } + + /* Add the block in debugfs */ + if (mem_block->free) + sprintf(mem_block->debugfs_fname, "%08lX free", + (unsigned long) mem_block->offset); + else { + sprintf(mem_block->debugfs_fname, "%08lX allc h:%08lX " + "lck:%d ", + (unsigned long) mem_block->offset, + (unsigned long) mem_block, + mem_block->lock_count); + } + + mem_block->debugfs_block = debugfs_create_file( + mem_block->debugfs_fname, + 0444, parent, mem_block, + &debugfs_b2r2_mem_block_fops); + if (mem_block->debugfs_block) { + mem_block->debugfs_block->d_inode->i_size = mem_block->size; + mem_block->debugfs_block->d_inode->i_atime = atime; + mem_block->debugfs_block->d_inode->i_mtime = mtime; + mem_block->debugfs_block->d_inode->i_ctime = ctime; + } +} +#endif /* CONFIG_DEBUG_FS */ + +/* Module initialization function */ +int b2r2_mem_init(struct b2r2_control *cont, + u32 heap_size, u32 align, u32 node_size) +{ + struct b2r2_mem_block *mem_block; + u32 aligned_size; + + dev_info(cont->dev, "%s: Creating heap for size %d bytes\n", + __func__, (int) heap_size); + + /* Align size */ + aligned_size = align_down(align, heap_size); + if (aligned_size == 0) + return -EINVAL; + + cont->mem_heap.start_virt_ptr = dma_alloc_coherent(cont->dev, + aligned_size, &(cont->mem_heap.start_phys_addr), GFP_KERNEL); + if (!cont->mem_heap.start_phys_addr || !cont->mem_heap.start_virt_ptr) { + printk(KERN_ERR "B2R2_MEM: Failed to allocate memory\n"); + return -ENOMEM; + } + + /* Initialize the heap */ + cont->mem_heap.size = aligned_size; + cont->mem_heap.align = align; + + INIT_LIST_HEAD(&cont->mem_heap.blocks); + +#ifdef CONFIG_DEBUG_FS + /* Register debugfs */ + if (cont->mem_heap.debugfs_root_dir) { + cont->mem_heap.debugfs_heap_stats = debugfs_create_file( + "stats", 0444, cont->mem_heap.debugfs_root_dir, + &cont->mem_heap, &debugfs_b2r2_mem_stats_fops); + cont->mem_heap.debugfs_dir_blocks = debugfs_create_dir( + "blocks", cont->mem_heap.debugfs_root_dir); + } +#endif + + /* Create the first _free_ memory block */ + mem_block = b2r2_mem_block_alloc(cont, 0, aligned_size, true); + if (!mem_block) { + dma_free_coherent(cont->dev, aligned_size, + cont->mem_heap.start_virt_ptr, + cont->mem_heap.start_phys_addr); + printk(KERN_ERR "B2R2_MEM: Failed to allocate memory\n"); + return -ENOMEM; + } + + /* Add the free block to the blocks list */ + list_add(&mem_block->list, &cont->mem_heap.blocks); + + /* Allocate separate heap for B2R2 nodes */ + cont->mem_heap.node_size = node_size; + cont->mem_heap.node_heap = dma_pool_create("b2r2_node_cache", + cont->dev, node_size, align, 4096); + if (!cont->mem_heap.node_heap) { + b2r2_mem_block_free(mem_block); + dma_free_coherent(cont->dev, aligned_size, + cont->mem_heap.start_virt_ptr, + cont->mem_heap.start_phys_addr); + printk(KERN_ERR "B2R2_MEM: Failed to allocate memory\n"); + return -ENOMEM; + } + + return 0; +} +EXPORT_SYMBOL(b2r2_mem_init); + +/* Module exit function */ +void b2r2_mem_exit(struct b2r2_control *cont) +{ + struct list_head *ptr; + + /* Free B2R2 node heap */ + dma_pool_destroy(cont->mem_heap.node_heap); + + list_for_each(ptr, &cont->mem_heap.blocks) { + struct b2r2_mem_block *mem_block = + list_entry(ptr, struct b2r2_mem_block, list); + + b2r2_mem_block_free(mem_block); + } + + dma_free_coherent(cont->dev, cont->mem_heap.size, + cont->mem_heap.start_virt_ptr, + cont->mem_heap.start_phys_addr); +} +EXPORT_SYMBOL(b2r2_mem_exit); + +/* Return status of the heap */ +static int b2r2_mem_heap_status(struct b2r2_mem_heap *mheap, + struct b2r2_mem_heap_status *mem_heap_status) +{ + struct list_head *ptr; + + if (!mheap || !mem_heap_status) + return -EINVAL; + memset(mem_heap_status, 0, sizeof(*mem_heap_status)); + + /* Lock the heap */ + spin_lock(&mheap->heap_lock); + + /* Fill in static info */ + mem_heap_status->start_phys_addr = mheap->start_phys_addr; + mem_heap_status->size = mheap->size; + mem_heap_status->align = mheap->align; + + list_for_each(ptr, &mheap->blocks) { + struct b2r2_mem_block *mem_block = + list_entry(ptr, struct b2r2_mem_block, list); + + if (mem_block->free) { + mem_heap_status->num_free++; + mem_heap_status->free_size += mem_block->size; + } else { + if (mem_block->lock_count) { + mem_heap_status->num_locked++; + mem_heap_status->num_locks += + mem_block->lock_count; + } + mem_heap_status->num_alloc++; + mem_heap_status->allocated_size += mem_block->size; + } + } + + spin_unlock(&mheap->heap_lock); + + return 0; +} +EXPORT_SYMBOL(b2r2_mem_heap_status); + +/* Internal: Allocate a housekeeping structure + * for an allocated or free memory block + */ +static struct b2r2_mem_block *b2r2_mem_block_alloc( + struct b2r2_control *cont, u32 offset, u32 size, bool free) +{ + struct b2r2_mem_block *mem_block = kmalloc( + sizeof(struct b2r2_mem_block), GFP_KERNEL); + + if (mem_block) { + mem_block->offset = offset; + mem_block->size = size; + mem_block->free = free; + mem_block->lock_count = 0; + + INIT_LIST_HEAD(&mem_block->list); + +#ifdef CONFIG_DEBUG_FS + mem_block->debugfs_block = NULL; + /* Add the block in debugfs */ + debugfs_create_mem_block_entry(mem_block, + cont->mem_heap.debugfs_dir_blocks); +#endif + } + + return mem_block; +} + +/* Internal: Release housekeeping structure */ +static void b2r2_mem_block_free(struct b2r2_mem_block *mem_block) +{ + if (mem_block) { +#ifdef CONFIG_DEBUG_FS + debugfs_remove(mem_block->debugfs_block); +#endif + kfree(mem_block); + } +} + +/* Allocate a block from the heap */ +int b2r2_mem_alloc(struct b2r2_control *cont, u32 requested_size, + u32 *returned_size, u32 *mem_handle) +{ + int ret = 0; + struct list_head *ptr; + struct b2r2_mem_block *found_mem_block = NULL; + u32 aligned_size; + + if (!mem_handle) + return -EINVAL; + + printk(KERN_INFO "%s: size=%d\n", __func__, requested_size); + + *mem_handle = 0; + + /* Lock the heap */ + spin_lock(&cont->mem_heap.heap_lock); + + aligned_size = align_up(cont->mem_heap.align, requested_size); + /* Try to find the best matching free block of suitable size */ + list_for_each(ptr, &cont->mem_heap.blocks) { + struct b2r2_mem_block *mem_block = + list_entry(ptr, struct b2r2_mem_block, list); + + if (mem_block->free && mem_block->size >= aligned_size && + (!found_mem_block || + mem_block->size < found_mem_block->size)) { + found_mem_block = mem_block; + if (found_mem_block->size == aligned_size) + break; + } + } + + if (found_mem_block) { + struct b2r2_mem_block *new_block + = b2r2_mem_block_alloc(cont, + found_mem_block->offset, + requested_size, false); + + if (new_block) { + /* Insert the new block before the found block */ + list_add_tail(&new_block->list, + &found_mem_block->list); + + /* Split the free block */ + found_mem_block->offset += aligned_size; + found_mem_block->size -= aligned_size; + + if (found_mem_block->size == 0) + b2r2_mem_block_free(found_mem_block); + else { +#ifdef CONFIG_DEBUG_FS + debugfs_create_mem_block_entry( + found_mem_block, + cont->mem_heap.debugfs_dir_blocks); +#endif + } + + *mem_handle = (u32) new_block; + *returned_size = aligned_size; + } else { + ret = -ENOMEM; + } + } else + ret = -ENOMEM; + + if (ret != 0) { + *returned_size = 0; + *mem_handle = (u32) 0; + } + + /* Unlock */ + spin_unlock(&cont->mem_heap.heap_lock); + + return ret; +} +EXPORT_SYMBOL(b2r2_mem_alloc); + +/* Free the allocated block */ +int b2r2_mem_free(struct b2r2_control *cont, u32 mem_handle) +{ + int ret = 0; + struct b2r2_mem_block *mem_block = (struct b2r2_mem_block *) mem_handle; + + if (!mem_block) + return -EINVAL; + + /* Lock the heap */ + spin_lock(&cont->mem_heap.heap_lock); + + if (!ret && mem_block->free) + ret = -EINVAL; + + if (!ret) { + printk(KERN_INFO "%s: freeing block 0x%p\n", __func__, mem_block); + /* Release the block */ + + mem_block->free = true; + mem_block->size = align_up(cont->mem_heap.align, + mem_block->size); + + /* Join with previous block if possible */ + if (mem_block->list.prev != &cont->mem_heap.blocks) { + struct b2r2_mem_block *prev_block = + list_entry(mem_block->list.prev, + struct b2r2_mem_block, list); + + if (prev_block->free && + (prev_block->offset + prev_block->size) == + mem_block->offset) { + mem_block->offset = prev_block->offset; + mem_block->size += prev_block->size; + + b2r2_mem_block_free(prev_block); + } + } + + /* Join with next block if possible */ + if (mem_block->list.next != &cont->mem_heap.blocks) { + struct b2r2_mem_block *next_block + = list_entry(mem_block->list.next, + struct b2r2_mem_block, + list); + + if (next_block->free && + (mem_block->offset + mem_block->size) == + next_block->offset) { + mem_block->size += next_block->size; + + b2r2_mem_block_free(next_block); + } + } +#ifdef CONFIG_DEBUG_FS + debugfs_create_mem_block_entry(mem_block, + cont->mem_heap.debugfs_dir_blocks); +#endif + } + + /* Unlock */ + spin_unlock(&cont->mem_heap.heap_lock); + + return ret; +} +EXPORT_SYMBOL(b2r2_mem_free); + +/* Lock the allocated block in memory */ +int b2r2_mem_lock(struct b2r2_control *cont, u32 mem_handle, + u32 *phys_addr, void **virt_ptr, u32 *size) +{ + struct b2r2_mem_block *mem_block = + (struct b2r2_mem_block *) mem_handle; + + if (!mem_block) + return -EINVAL; + + /* Lock the heap */ + spin_lock(&cont->mem_heap.heap_lock); + + mem_block->lock_count++; + + if (phys_addr) + *phys_addr = cont->mem_heap.start_phys_addr + mem_block->offset; + if (virt_ptr) + *virt_ptr = (char *) cont->mem_heap.start_virt_ptr + + mem_block->offset; + if (size) + *size = align_up(cont->mem_heap.align, mem_block->size); +#ifdef CONFIG_DEBUG_FS + debugfs_create_mem_block_entry(mem_block, + cont->mem_heap.debugfs_dir_blocks); +#endif + + spin_unlock(&cont->mem_heap.heap_lock); + + return 0; +} +EXPORT_SYMBOL(b2r2_mem_lock); + +/* Unlock the allocated block in memory */ +int b2r2_mem_unlock(struct b2r2_control *cont, u32 mem_handle) +{ + struct b2r2_mem_block *mem_block = + (struct b2r2_mem_block *) mem_handle; + + if (!mem_block) + return -EINVAL; + + /* Lock the heap */ + spin_lock(&cont->mem_heap.heap_lock); + + mem_block->lock_count--; + + spin_unlock(&cont->mem_heap.heap_lock); + + /* debugfs will be updated in release */ + return 0; +/* return b2r2_mem_free(mem_handle);*/ +} +EXPORT_SYMBOL(b2r2_mem_unlock); + +/* Allocate one or more b2r2 nodes from DMA pool */ +int b2r2_node_alloc(struct b2r2_control *cont, u32 num_nodes, + struct b2r2_node **first_node) +{ + int i; + int ret = 0; + u32 physical_address; + struct b2r2_node *first_node_ptr; + struct b2r2_node *node_ptr; + + /* Check input parameters */ + if ((num_nodes <= 0) || !first_node) { + dev_err(cont->dev, + "B2R2_MEM: Invalid parameter for b2r2_node_alloc, " + "num_nodes=%d, first_node=%ld\n", + (int) num_nodes, (long) first_node); + return -EINVAL; + } + + /* Allocate the first node */ + first_node_ptr = dma_pool_alloc(cont->mem_heap.node_heap, + GFP_DMA | GFP_KERNEL, &physical_address); + if (!first_node_ptr) { + dev_err(cont->dev, + "B2R2_MEM: Failed to allocate memory for node\n"); + return -ENOMEM; + } + + /* Initialize first node */ + first_node_ptr->next = NULL; + first_node_ptr->physical_address = physical_address + + offsetof(struct b2r2_node, node); + + /* Allocate and initialize remaining nodes, */ + /* and link them into a list */ + for (i = 1, node_ptr = first_node_ptr; i < num_nodes; i++) { + node_ptr->next = dma_pool_alloc(cont->mem_heap.node_heap, + GFP_DMA | GFP_KERNEL, &physical_address); + if (node_ptr->next) { + node_ptr = node_ptr->next; + node_ptr->next = NULL; + node_ptr->physical_address = physical_address + + offsetof(struct b2r2_node, node); + } else { + printk(KERN_ERR "B2R2_MEM: Failed to allocate memory for node\n"); + ret = -ENOMEM; + break; + } + } + + /* If all nodes were allocated successfully, */ + /* return the first node */ + if (!ret) + *first_node = first_node_ptr; + else + b2r2_node_free(cont, first_node_ptr); + + return ret; +} +EXPORT_SYMBOL(b2r2_node_alloc); + +/* Free a linked list of b2r2 nodes */ +void b2r2_node_free(struct b2r2_control *cont, struct b2r2_node *first_node) +{ + struct b2r2_node *current_node = first_node; + struct b2r2_node *next_node = NULL; + + /* Traverse the linked list and free the nodes */ + while (current_node != NULL) { + next_node = current_node->next; + dma_pool_free(cont->mem_heap.node_heap, current_node, + current_node->physical_address - + offsetof(struct b2r2_node, node)); + current_node = next_node; + } +} +EXPORT_SYMBOL(b2r2_node_free); + +MODULE_AUTHOR("Robert Lind <robert.lind@ericsson.com"); +MODULE_DESCRIPTION("Ericsson AB B2R2 physical memory driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/b2r2/b2r2_mem_alloc.h b/drivers/video/b2r2/b2r2_mem_alloc.h new file mode 100644 index 00000000000..4fd1e66abca --- /dev/null +++ b/drivers/video/b2r2/b2r2_mem_alloc.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 internal Memory allocator + * + * Author: Robert Lind <robert.lind@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __B2R2_MEM_ALLOC_H +#define __B2R2_MEM_ALLOC_H + +#include "b2r2_internal.h" + + +/** + * struct b2r2_mem_heap_status - Information about current state of the heap + * + * @start_phys_addr: Physical address of the the memory area + * @size: Size of the memory area + * @align: Alignment of start and allocation sizes (in bytes). + * @num_alloc: Number of memory allocations + * @allocated_size: Size allocated (sum of requested sizes) + * @num_free: Number of free blocks (fragments) + * @free_size: Free size available for allocation + * @num_locks: Sum of number of number of locks on memory allocations + * @num_locked: Number of locked memory allocations + * @num_nodes: Number of node allocations + * + **/ +struct b2r2_mem_heap_status { + u32 start_phys_addr; + u32 size; + u32 align; + u32 num_alloc; + u32 allocated_size; + u32 num_free; + u32 free_size; + u32 num_locks; + u32 num_locked; + u32 num_nodes; +}; + +/** + * struct b2r2_mem_block - Represents one block of b2r2 + * physical memory, free or allocated + * + * @list: For membership in list + * @offset: Offset in b2r2 physical memory area (aligned) + * @size: Size of the object (requested size if busy, else actual) + * @free: True if the block is free + * @lock_count: Lock count + * @debugfs_fname: Debugfs file name + * @debugfs_block: Debugfs dir entry for the block + */ +struct b2r2_mem_block { + struct list_head list; + u32 offset; + u32 size; + bool free; + u32 lock_count; +#ifdef CONFIG_DEBUG_FS + char debugfs_fname[80]; + struct dentry *debugfs_block; +#endif +}; + + +/* B2R2 memory API (kernel) */ + +/** + * b2r2_mem_init() - Initializes the B2R2 memory manager + * @dev: Pointer to device to use for allocating the memory heap + * @heap_size: Size of the heap (in bytes) + * @align: Alignment to use for memory allocations on heap (in bytes) + * @node_size: Size of each B2R2 node (in bytes) + * + * Returns 0 if success, else negative error code + **/ +int b2r2_mem_init(struct b2r2_control *cont, + u32 heap_size, u32 align, u32 node_size); + +/** + * b2r2_mem_exit() - Cleans up the B2R2 memory manager + * + **/ +void b2r2_mem_exit(struct b2r2_control *cont); + +/** + * b2r2_mem_alloc() - Allocates memory block from physical memory heap + * @requested_size: Requested size + * @returned_size: Actual size of memory block. Might be adjusted due to + * alignment but is always >= requested size if function + * succeeds + * @mem_handle: Returned memory handle + * + * All memory allocations are movable when not locked. + * Returns 0 if OK else negative error value + **/ +int b2r2_mem_alloc(struct b2r2_control *cont, u32 requested_size, + u32 *returned_size, u32 *mem_handle); + +/** + * b2r2_mem_free() - Frees an allocation + * @mem_handle: Memory handle + * + * Returns 0 if OK else negative error value + **/ +int b2r2_mem_free(struct b2r2_control *cont, u32 mem_handle); + +/** + * b2r2_mem_lock() - Lock memory in memory and return physical address + * @mem_handle: Memory handle + * @phys_addr: Returned physical address to start of memory allocation. + * May be NULL. + * @virt_ptr: Returned virtual address pointer to start of memory allocation. + * May be NULL. + * @size: Returned size of memory allocation. May be NULL. + * + * The adress of the memory allocation is locked and the physical address + * is returned. + * The lock count is incremented by one. + * You need to call b2r2_mem_unlock once for each call to + * b2r2_mem_lock. + * Returns 0 if OK else negative error value + **/ +int b2r2_mem_lock(struct b2r2_control *cont, u32 mem_handle, + u32 *phys_addr, void **virt_ptr, u32 *size); + +/** + * b2r2_mem_unlock() - Unlock previously locked memory + * @mem_handle: Memory handle + * + * Decrements lock count. When lock count reaches 0 the + * memory area is movable again. + * Returns 0 if OK else negative error value + **/ +int b2r2_mem_unlock(struct b2r2_control *cont, u32 mem_handle); + +/** + * b2r2_node_alloc() - Allocates B2R2 node from physical memory heap + * @num_nodes: Number of linked nodes to allocate + * @first_node: Returned pointer to first node in linked list + * + * Returns 0 if OK else negative error value + **/ +int b2r2_node_alloc(struct b2r2_control *cont, u32 num_nodes, + struct b2r2_node **first_node); + +/** + * b2r2_node_free() - Frees a linked list of allocated B2R2 nodes + * @first_node: Pointer to first node in linked list + * + * Returns 0 if OK else negative error value + **/ +void b2r2_node_free(struct b2r2_control *cont, struct b2r2_node *first_node); + + +#endif /* __B2R2_MEM_ALLOC_H */ diff --git a/drivers/video/b2r2/b2r2_node_gen.c b/drivers/video/b2r2/b2r2_node_gen.c new file mode 100644 index 00000000000..1f48bac6fe7 --- /dev/null +++ b/drivers/video/b2r2/b2r2_node_gen.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 node generator + * + * Author: Robert Fekete <robert.fekete@stericsson.com> + * Author: Paul Wannback + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <asm/dma-mapping.h> +#include "b2r2_internal.h" + +static void free_nodes(struct b2r2_control *cont, + struct b2r2_node *first_node) +{ + struct b2r2_node *node = first_node; + int no_of_nodes = 0; + + while (node) { + no_of_nodes++; + node = node->next; + } + + dma_free_coherent(cont->dev, + no_of_nodes * sizeof(struct b2r2_node), + first_node, + first_node->physical_address - + offsetof(struct b2r2_node, node)); +} + +struct b2r2_node *b2r2_blt_alloc_nodes(struct b2r2_control *cont, + int no_of_nodes) +{ + u32 physical_address; + struct b2r2_node *nodes; + struct b2r2_node *tmpnode; + + if (no_of_nodes <= 0) { + dev_err(cont->dev, "%s: Wrong number of nodes (%d)", + __func__, no_of_nodes); + return NULL; + } + + /* Allocate the memory */ + nodes = (struct b2r2_node *) dma_alloc_coherent(cont->dev, + no_of_nodes * sizeof(struct b2r2_node), + &physical_address, GFP_DMA | GFP_KERNEL); + + if (nodes == NULL) { + dev_err(cont->dev, + "%s: Failed to alloc memory for nodes", + __func__); + return NULL; + } + + /* Build the linked list */ + tmpnode = nodes; + physical_address += offsetof(struct b2r2_node, node); + while (no_of_nodes--) { + tmpnode->physical_address = physical_address; + if (no_of_nodes) + tmpnode->next = tmpnode + 1; + else + tmpnode->next = NULL; + + tmpnode++; + physical_address += sizeof(struct b2r2_node); + } + + return nodes; +} + +void b2r2_blt_free_nodes(struct b2r2_control *cont, + struct b2r2_node *first_node) +{ + free_nodes(cont, first_node); +} + diff --git a/drivers/video/b2r2/b2r2_node_split.c b/drivers/video/b2r2/b2r2_node_split.c new file mode 100644 index 00000000000..6587ef0c343 --- /dev/null +++ b/drivers/video/b2r2/b2r2_node_split.c @@ -0,0 +1,3734 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 node splitter + * + * Author: Fredrik Allansson <fredrik.allansson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include "b2r2_debug.h" +#include "b2r2_node_split.h" +#include "b2r2_internal.h" +#include "b2r2_hw.h" +#include "b2r2_filters.h" +#include "b2r2_utils.h" + +#include <linux/kernel.h> + +/* + * Macros and constants + */ +#define ABS(x) ((x) < 0 ? -(x) : (x)) +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +#define INSTANCES_DEFAULT_SIZE 10 +#define INSTANCES_GROW_SIZE 5 + +/* + * Internal types + */ + + +/* + * Global variables + */ + +/** + * VMX values for different color space conversions + */ +static const u32 vmx_rgb_to_yuv[] = { + B2R2_VMX0_RGB_TO_YUV_601_VIDEO, + B2R2_VMX1_RGB_TO_YUV_601_VIDEO, + B2R2_VMX2_RGB_TO_YUV_601_VIDEO, + B2R2_VMX3_RGB_TO_YUV_601_VIDEO, +}; + +static const u32 vmx_rgb_to_blt_yuv888[] = { + B2R2_VMX0_RGB_TO_BLT_YUV888_601_VIDEO, + B2R2_VMX1_RGB_TO_BLT_YUV888_601_VIDEO, + B2R2_VMX2_RGB_TO_BLT_YUV888_601_VIDEO, + B2R2_VMX3_RGB_TO_BLT_YUV888_601_VIDEO, +}; + +static const u32 vmx_yuv_to_rgb[] = { + B2R2_VMX0_YUV_TO_RGB_601_VIDEO, + B2R2_VMX1_YUV_TO_RGB_601_VIDEO, + B2R2_VMX2_YUV_TO_RGB_601_VIDEO, + B2R2_VMX3_YUV_TO_RGB_601_VIDEO, +}; + +static const u32 vmx_blt_yuv888_to_rgb[] = { + B2R2_VMX0_BLT_YUV888_TO_RGB_601_VIDEO, + B2R2_VMX1_BLT_YUV888_TO_RGB_601_VIDEO, + B2R2_VMX2_BLT_YUV888_TO_RGB_601_VIDEO, + B2R2_VMX3_BLT_YUV888_TO_RGB_601_VIDEO, +}; + +static const u32 vmx_yuv_to_blt_yuv888[] = { + B2R2_VMX0_YUV_TO_BLT_YUV888, + B2R2_VMX1_YUV_TO_BLT_YUV888, + B2R2_VMX2_YUV_TO_BLT_YUV888, + B2R2_VMX3_YUV_TO_BLT_YUV888, +}; + +static const u32 vmx_blt_yuv888_to_yuv[] = { + B2R2_VMX0_BLT_YUV888_TO_YUV, + B2R2_VMX1_BLT_YUV888_TO_YUV, + B2R2_VMX2_BLT_YUV888_TO_YUV, + B2R2_VMX3_BLT_YUV888_TO_YUV, +}; + +static const u32 vmx_yvu_to_blt_yuv888[] = { + B2R2_VMX0_YVU_TO_BLT_YUV888, + B2R2_VMX1_YVU_TO_BLT_YUV888, + B2R2_VMX2_YVU_TO_BLT_YUV888, + B2R2_VMX3_YVU_TO_BLT_YUV888, +}; + +static const u32 vmx_blt_yuv888_to_yvu[] = { + B2R2_VMX0_BLT_YUV888_TO_YVU, + B2R2_VMX1_BLT_YUV888_TO_YVU, + B2R2_VMX2_BLT_YUV888_TO_YVU, + B2R2_VMX3_BLT_YUV888_TO_YVU, +}; + +static const u32 vmx_yvu_to_rgb[] = { + B2R2_VMX0_YVU_TO_RGB_601_VIDEO, + B2R2_VMX1_YVU_TO_RGB_601_VIDEO, + B2R2_VMX2_YVU_TO_RGB_601_VIDEO, + B2R2_VMX3_YVU_TO_RGB_601_VIDEO, +}; + +static const u32 vmx_rgb_to_yvu[] = { + B2R2_VMX0_RGB_TO_YVU_601_VIDEO, + B2R2_VMX1_RGB_TO_YVU_601_VIDEO, + B2R2_VMX2_RGB_TO_YVU_601_VIDEO, + B2R2_VMX3_RGB_TO_YVU_601_VIDEO, +}; + +static const u32 vmx_rgb_to_bgr[] = { + B2R2_VMX0_RGB_TO_BGR, + B2R2_VMX1_RGB_TO_BGR, + B2R2_VMX2_RGB_TO_BGR, + B2R2_VMX3_RGB_TO_BGR, +}; + +static const u32 vmx_bgr_to_yuv[] = { + B2R2_VMX0_BGR_TO_YUV_601_VIDEO, + B2R2_VMX1_BGR_TO_YUV_601_VIDEO, + B2R2_VMX2_BGR_TO_YUV_601_VIDEO, + B2R2_VMX3_BGR_TO_YUV_601_VIDEO, +}; + +static const u32 vmx_yuv_to_bgr[] = { + B2R2_VMX0_YUV_TO_BGR_601_VIDEO, + B2R2_VMX1_YUV_TO_BGR_601_VIDEO, + B2R2_VMX2_YUV_TO_BGR_601_VIDEO, + B2R2_VMX3_YUV_TO_BGR_601_VIDEO, +}; + +static const u32 vmx_bgr_to_yvu[] = { + B2R2_VMX0_BGR_TO_YVU_601_VIDEO, + B2R2_VMX1_BGR_TO_YVU_601_VIDEO, + B2R2_VMX2_BGR_TO_YVU_601_VIDEO, + B2R2_VMX3_BGR_TO_YVU_601_VIDEO, +}; + +static const u32 vmx_yvu_to_bgr[] = { + B2R2_VMX0_YVU_TO_BGR_601_VIDEO, + B2R2_VMX1_YVU_TO_BGR_601_VIDEO, + B2R2_VMX2_YVU_TO_BGR_601_VIDEO, + B2R2_VMX3_YVU_TO_BGR_601_VIDEO, +}; + +static const u32 vmx_yvu_to_yuv[] = { + B2R2_VMX0_YVU_TO_YUV_601_VIDEO, + B2R2_VMX1_YVU_TO_YUV_601_VIDEO, + B2R2_VMX2_YVU_TO_YUV_601_VIDEO, + B2R2_VMX3_YVU_TO_YUV_601_VIDEO, +}; + +/* + * Forward declaration of private functions + */ +static int analyze_fmt_conv(struct b2r2_control *cont, + struct b2r2_node_split_buf *src, + struct b2r2_node_split_buf *dst, + const u32 **vmx, u32 *node_count); +static int analyze_color_fill(struct b2r2_node_split_job *this, + const struct b2r2_blt_request *req, u32 *node_count); +static int analyze_copy(struct b2r2_node_split_job *this, + const struct b2r2_blt_request *req, u32 *node_count, + u32 *buf_count); +static int analyze_scaling(struct b2r2_node_split_job *this, + const struct b2r2_blt_request *req, u32 *node_count, + u32 *buf_count); +static int analyze_rotate(struct b2r2_node_split_job *this, + const struct b2r2_blt_request *req, u32 *node_count, + u32 *buf_count); +static int analyze_transform(struct b2r2_node_split_job *this, + const struct b2r2_blt_request *req, u32 *node_count, + u32 *buf_count); +static int analyze_rot_scale(struct b2r2_node_split_job *this, + const struct b2r2_blt_request *req, u32 *node_count, + u32 *buf_count); +static int analyze_scale_factors(struct b2r2_control *cont, + struct b2r2_node_split_job *this); + +static void configure_src(struct b2r2_control *cont, struct b2r2_node *node, + struct b2r2_node_split_buf *src, const u32 *ivmx); +static void configure_bg(struct b2r2_control *cont, struct b2r2_node *node, + struct b2r2_node_split_buf *bg, bool swap_fg_bg); +static int configure_dst(struct b2r2_control *cont, struct b2r2_node *node, + struct b2r2_node_split_buf *dst, const u32 *ivmx, + struct b2r2_node **next); +static void configure_blend(struct b2r2_control *cont, struct b2r2_node *node, + u32 flags, u32 global_alpha); +static void configure_clip(struct b2r2_control *cont, struct b2r2_node *node, + struct b2r2_blt_rect *clip_rect); + +static int configure_tile(struct b2r2_control *cont, + struct b2r2_node_split_job *this, struct b2r2_node *node, + struct b2r2_node **next); +static void configure_direct_fill(struct b2r2_control *cont, + struct b2r2_node *node, u32 color, + struct b2r2_node_split_buf *dst, + struct b2r2_node **next); +static int configure_fill(struct b2r2_control *cont, + struct b2r2_node *node, u32 color, enum b2r2_blt_fmt fmt, + struct b2r2_node_split_buf *dst, const u32 *ivmx, + struct b2r2_node **next); +static void configure_direct_copy(struct b2r2_control *cont, + struct b2r2_node *node, struct b2r2_node_split_buf *src, + struct b2r2_node_split_buf *dst, struct b2r2_node **next); +static int configure_copy(struct b2r2_control *cont, + struct b2r2_node *node, struct b2r2_node_split_buf *src, + struct b2r2_node_split_buf *dst, const u32 *ivmx, + struct b2r2_node **next, + struct b2r2_node_split_job *this); +static int configure_rotate(struct b2r2_control *cont, + struct b2r2_node *node, struct b2r2_node_split_buf *src, + struct b2r2_node_split_buf *dst, const u32 *ivmx, + struct b2r2_node **next, + struct b2r2_node_split_job *this); +static int configure_scale(struct b2r2_control *cont, + struct b2r2_node *node, struct b2r2_node_split_buf *src, + struct b2r2_node_split_buf *dst, u16 h_rsf, u16 v_rsf, + const u32 *ivmx, struct b2r2_node **next, + struct b2r2_node_split_job *this); +static int configure_rot_scale(struct b2r2_control *cont, + struct b2r2_node_split_job *this, struct b2r2_node *node, + struct b2r2_node **next); + +static void recalculate_rects(struct b2r2_control *cont, + struct b2r2_blt_req *req); + +static int check_rect(struct b2r2_control *cont, + const struct b2r2_blt_img *img, + const struct b2r2_blt_rect *rect, + const struct b2r2_blt_rect *clip); +static void set_buf(struct b2r2_control *cont, + struct b2r2_node_split_buf *buf, + u32 addr, const struct b2r2_blt_img *img, + const struct b2r2_blt_rect *rect, bool color_fill, u32 color); +static int setup_tmp_buf(struct b2r2_control *cont, + struct b2r2_node_split_buf *this, u32 max_size, + enum b2r2_blt_fmt pref_fmt, u32 pref_width, u32 pref_height); + +static enum b2r2_ty get_alpha_range(enum b2r2_blt_fmt fmt); +static u32 set_alpha(enum b2r2_blt_fmt fmt, u8 alpha, u32 color); +static u8 get_alpha(enum b2r2_blt_fmt fmt, u32 pixel); +static bool fmt_has_alpha(enum b2r2_blt_fmt fmt); + +static bool is_rgb_fmt(enum b2r2_blt_fmt fmt); +static bool is_bgr_fmt(enum b2r2_blt_fmt fmt); +static bool is_yuv_fmt(enum b2r2_blt_fmt fmt); +static bool is_yvu_fmt(enum b2r2_blt_fmt fmt); +static bool is_yuv420_fmt(enum b2r2_blt_fmt fmt); +static bool is_yuv422_fmt(enum b2r2_blt_fmt fmt); +static bool is_yuv444_fmt(enum b2r2_blt_fmt fmt); +static bool is_yvu420_fmt(enum b2r2_blt_fmt fmt); +static bool is_yvu422_fmt(enum b2r2_blt_fmt fmt); + +static int fmt_byte_pitch(enum b2r2_blt_fmt fmt, u32 width); +static enum b2r2_native_fmt to_native_fmt(enum b2r2_blt_fmt fmt); +static u32 to_RGB888(u32 color, const enum b2r2_blt_fmt fmt); +static enum b2r2_fmt_type get_fmt_type(enum b2r2_blt_fmt fmt); + +static bool is_transform(const struct b2r2_blt_request *req); +static s32 rescale(struct b2r2_control *cont, s32 dim, u16 sf); +static s32 inv_rescale(s32 dim, u16 sf); + +static void set_target(struct b2r2_node *node, u32 addr, + struct b2r2_node_split_buf *buf); +static void set_src(struct b2r2_src_config *src, u32 addr, + struct b2r2_node_split_buf *buf); +static void set_src_1(struct b2r2_node *node, u32 addr, + struct b2r2_node_split_buf *buf); +static void set_src_2(struct b2r2_node *node, u32 addr, + struct b2r2_node_split_buf *buf); +static void set_src_3(struct b2r2_node *node, u32 addr, + struct b2r2_node_split_buf *buf); +static void set_ivmx(struct b2r2_node *node, const u32 *vmx_values); + +static void reset_nodes(struct b2r2_node *node); + +static bool bg_format_require_ivmx(enum b2r2_blt_fmt bg_fmt, + enum b2r2_blt_fmt dst_fmt); + +/* + * Public functions + */ + +/** + * b2r2_node_split_analyze() - analyzes the request + */ +int b2r2_node_split_analyze(const struct b2r2_blt_request *req, + u32 max_buf_size, u32 *node_count, struct b2r2_work_buf **bufs, + u32 *buf_count, struct b2r2_node_split_job *this) +{ + int ret; + bool color_fill; + struct b2r2_control *cont = req->instance->control; + + b2r2_log_info(cont->dev, "%s\n", __func__); + + memset(this, 0, sizeof(*this)); + + /* Copy parameters */ + this->flags = req->user_req.flags; + this->transform = req->user_req.transform; + this->max_buf_size = max_buf_size; + this->global_alpha = req->user_req.global_alpha; + this->buf_count = 0; + this->node_count = 0; + + if (this->flags & B2R2_BLT_FLAG_BLUR) { + ret = -ENOSYS; + goto unsupported; + } + + /* Unsupported formats on src */ + switch (req->user_req.src_img.fmt) { + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + if (is_bgr_fmt(req->user_req.dst_img.fmt)) { + ret = -ENOSYS; + goto unsupported; + } + break; + default: + break; + } + + /* Unsupported formats on dst */ + switch (req->user_req.dst_img.fmt) { + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + if (is_bgr_fmt(req->user_req.src_img.fmt)) { + ret = -ENOSYS; + goto unsupported; + } + break; + default: + break; + } + + /* Unsupported formats on bg */ + if (this->flags & B2R2_BLT_FLAG_BG_BLEND) + /* + * There are no ivmx on source 1, so check that there is no + * such requirement on the background to destination format + * conversion. This check is sufficient since the node splitter + * currently does not support destination ivmx. That fact also + * removes the source format as a parameter when checking the + * background format. + */ + if (bg_format_require_ivmx(req->user_req.bg_img.fmt, + req->user_req.dst_img.fmt)) { + ret = -ENOSYS; + goto unsupported; + } + + if ((this->flags & B2R2_BLT_FLAG_SOURCE_COLOR_KEY) && + (is_yuv_fmt(req->user_req.src_img.fmt) || + req->user_req.src_img.fmt == B2R2_BLT_FMT_1_BIT_A1 || + req->user_req.src_img.fmt == B2R2_BLT_FMT_8_BIT_A8)) { + b2r2_log_warn(cont->dev, "%s: Unsupported: source color keying " + "with YUV or pure alpha formats.\n", __func__); + ret = -ENOSYS; + goto unsupported; + } + + if (this->flags & (B2R2_BLT_FLAG_DEST_COLOR_KEY | + B2R2_BLT_FLAG_SOURCE_MASK)) { + b2r2_log_warn(cont->dev, "%s: Unsupported: source mask, " + "destination color keying.\n", __func__); + ret = -ENOSYS; + goto unsupported; + } + + if ((req->user_req.flags & B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) && + req->user_req.clut == NULL) { + b2r2_log_warn(cont->dev, "%s: Invalid request: no table " + "specified for CLUT color correction.\n", + __func__); + return -EINVAL; + } + + /* Check for color fill */ + color_fill = (this->flags & (B2R2_BLT_FLAG_SOURCE_FILL | + B2R2_BLT_FLAG_SOURCE_FILL_RAW)) != 0; + + /* + * B2R2 cannot handle destination clipping on buffers + * allocated close to 64MiB bank boundaries. + * recalculate src_ and dst_rect to avoid clipping. + */ + recalculate_rects(cont, (struct b2r2_blt_req *) &req->user_req); + + /* Configure the source and destination buffers */ + set_buf(cont, &this->src, req->src_resolved.physical_address, + &req->user_req.src_img, &req->user_req.src_rect, + color_fill, req->user_req.src_color); + + if (this->flags & B2R2_BLT_FLAG_BG_BLEND) { + set_buf(cont, &this->bg, req->bg_resolved.physical_address, + &req->user_req.bg_img, &req->user_req.bg_rect, + false, 0); + } + + set_buf(cont, &this->dst, req->dst_resolved.physical_address, + &req->user_req.dst_img, &req->user_req.dst_rect, false, + 0); + + b2r2_log_info(cont->dev, "%s:\n" + "\t\tsrc.rect=(%4d, %4d, %4d, %4d)\t" + "bg.rect=(%4d, %4d, %4d, %4d)\t" + "dst.rect=(%4d, %4d, %4d, %4d)\n", __func__, this->src.rect.x, + this->src.rect.y, this->src.rect.width, this->src.rect.height, + this->bg.rect.x, this->bg.rect.y, this->bg.rect.width, + this->bg.rect.height, this->dst.rect.x, this->dst.rect.y, + this->dst.rect.width, this->dst.rect.height); + + if (this->flags & B2R2_BLT_FLAG_DITHER) + this->dst.dither = B2R2_TTY_RGB_ROUND_DITHER; + + if (this->flags & B2R2_BLT_FLAG_SOURCE_COLOR_KEY) + this->flag_param = req->user_req.src_color; + + /* Check for blending */ + if ((this->flags & B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND) && + (this->global_alpha != 255)) + this->blend = true; + else if (this->flags & B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND) + this->blend = (color_fill && fmt_has_alpha(this->dst.fmt)) || + fmt_has_alpha(this->src.fmt); + else if (this->flags & B2R2_BLT_FLAG_BG_BLEND) + this->blend = true; + + if (this->blend && this->src.type == B2R2_FMT_TYPE_PLANAR) { + b2r2_log_warn(cont->dev, "%s: Unsupported: blend with planar" + " source\n", __func__); + ret = -ENOSYS; + goto unsupported; + } + + /* Check for clipping */ + this->clip = (this->flags & B2R2_BLT_FLAG_DESTINATION_CLIP) != 0; + if (this->clip) { + s32 l = req->user_req.dst_clip_rect.x; + s32 r = l + req->user_req.dst_clip_rect.width; + s32 t = req->user_req.dst_clip_rect.y; + s32 b = t + req->user_req.dst_clip_rect.height; + + /* Intersect the clip and buffer rects */ + if (l < 0) + l = 0; + if (r > req->user_req.dst_img.width) + r = req->user_req.dst_img.width; + if (t < 0) + t = 0; + if (b > req->user_req.dst_img.height) + b = req->user_req.dst_img.height; + + this->clip_rect.x = l; + this->clip_rect.y = t; + this->clip_rect.width = r - l; + this->clip_rect.height = b - t; + } else { + /* Set the clip rectangle to the buffer bounds */ + this->clip_rect.x = 0; + this->clip_rect.y = 0; + this->clip_rect.width = req->user_req.dst_img.width; + this->clip_rect.height = req->user_req.dst_img.height; + } + + /* Validate the destination */ + ret = check_rect(cont, &req->user_req.dst_img, &req->user_req.dst_rect, + &this->clip_rect); + if (ret < 0) + goto error; + + /* Validate the source (if not color fill) */ + if (!color_fill) { + ret = check_rect(cont, &req->user_req.src_img, + &req->user_req.src_rect, NULL); + if (ret < 0) + goto error; + } + + /* Validate the background source */ + if (this->flags & B2R2_BLT_FLAG_BG_BLEND) { + ret = check_rect(cont, &req->user_req.bg_img, + &req->user_req.bg_rect, NULL); + if (ret < 0) + goto error; + } + + /* Do the analysis depending on the type of operation */ + if (color_fill) { + ret = analyze_color_fill(this, req, &this->node_count); + } else { + + bool upsample; + bool downsample; + + /* + * YUV formats that are non-raster, non-yuv444 needs to be + * up (or down) sampled using the resizer. + * + * NOTE: The resizer needs to be enabled for YUV444 as well, + * even though there is no upsampling. This is most + * likely a bug in the hardware. + */ + upsample = this->src.type != B2R2_FMT_TYPE_RASTER && + is_yuv_fmt(this->src.fmt); + downsample = this->dst.type != B2R2_FMT_TYPE_RASTER && + is_yuv_fmt(this->dst.fmt); + + if (is_transform(req) || upsample || downsample) + ret = analyze_transform(this, req, &this->node_count, + &this->buf_count); + else + ret = analyze_copy(this, req, &this->node_count, + &this->buf_count); + } + + if (ret == -ENOSYS) { + goto unsupported; + } else if (ret < 0) { + b2r2_log_warn(cont->dev, "%s: Analysis failed!\n", __func__); + goto error; + } + + /* Setup the origin and movement of the destination window */ + if (this->dst.hso == B2R2_TY_HSO_RIGHT_TO_LEFT) { + this->dst.dx = -this->dst.win.width; + this->dst.win.x = this->dst.rect.x + this->dst.rect.width - 1; + } else { + this->dst.dx = this->dst.win.width; + this->dst.win.x = this->dst.rect.x; + } + if (this->dst.vso == B2R2_TY_VSO_BOTTOM_TO_TOP) { + this->dst.dy = -this->dst.win.height; + this->dst.win.y = this->dst.rect.y + this->dst.rect.height - 1; + } else { + this->dst.dy = this->dst.win.height; + this->dst.win.y = this->dst.rect.y; + } + + *buf_count = this->buf_count; + *node_count = this->node_count; + + if (this->buf_count > 0) + *bufs = &this->work_bufs[0]; + + b2r2_log_info(cont->dev, "%s: dst.win=(%d, %d, %d, %d), " + "dst.dx=%d, dst.dy=%d\n", __func__, this->dst.win.x, + this->dst.win.y, this->dst.win.width, this->dst.win.height, + this->dst.dx, this->dst.dy); + if (this->buf_count > 0) + b2r2_log_info(cont->dev, "%s: buf_count=%d, buf_size=%d, " + "node_count=%d\n", __func__, *buf_count, + bufs[0]->size, *node_count); + else + b2r2_log_info(cont->dev, "%s: buf_count=%d, node_count=%d\n", + __func__, *buf_count, *node_count); + + return 0; + +error: + b2r2_log_warn(cont->dev, "%s: Exit...\n", __func__); +unsupported: + return ret; +} + +/** + * b2r2_node_split_configure() - configures the node list + */ +int b2r2_node_split_configure(struct b2r2_control *cont, + struct b2r2_node_split_job *this, struct b2r2_node *first) +{ + int ret; + + struct b2r2_node_split_buf *dst = &this->dst; + struct b2r2_node *node = first; + + u32 x_pixels = 0; + u32 y_pixels = 0; + + reset_nodes(node); + + while (y_pixels < dst->rect.height) { + s32 dst_x = dst->win.x; + s32 dst_w = dst->win.width; + + /* Clamp window height */ + if (dst->win.height > dst->rect.height - y_pixels) + dst->win.height = dst->rect.height - y_pixels; + + while (x_pixels < dst->rect.width) { + + /* Clamp window width */ + if (dst_w > dst->rect.width - x_pixels) + dst->win.width = dst->rect.width - x_pixels; + + ret = configure_tile(cont, this, node, &node); + if (ret < 0) + goto error; + + dst->win.x += dst->dx; + x_pixels += max(dst->dx, -dst->dx); + b2r2_log_info(cont->dev, "%s: x_pixels=%d\n", + __func__, x_pixels); + } + + dst->win.y += dst->dy; + y_pixels += max(dst->dy, -dst->dy); + + dst->win.x = dst_x; + dst->win.width = dst_w; + x_pixels = 0; + + b2r2_log_info(cont->dev, "%s: y_pixels=%d\n", + __func__, y_pixels); + } + + return 0; + +error: + b2r2_log_warn(cont->dev, "%s: error!\n", __func__); + return ret; +} + +/** + * b2r2_node_split_assign_buffers() - assigns temporary buffers to the node list + */ +int b2r2_node_split_assign_buffers(struct b2r2_control *cont, + struct b2r2_node_split_job *this, struct b2r2_node *first, + struct b2r2_work_buf *bufs, u32 buf_count) +{ + struct b2r2_node *node = first; + + while (node != NULL) { + /* The indices are offset by one */ + if (node->dst_tmp_index) { + BUG_ON(node->dst_tmp_index > buf_count); + + b2r2_log_info(cont->dev, "%s: assigning buf %d as " + "dst\n", __func__, node->dst_tmp_index); + + node->node.GROUP1.B2R2_TBA = + bufs[node->dst_tmp_index - 1].phys_addr; + } + if (node->src_tmp_index) { + u32 addr = bufs[node->src_tmp_index - 1].phys_addr; + + b2r2_log_info(cont->dev, "%s: assigning buf %d as src " + "%d ", __func__, node->src_tmp_index, + node->src_index); + + BUG_ON(node->src_tmp_index > buf_count); + + switch (node->src_index) { + case 1: + b2r2_log_info(cont->dev, "1\n"); + node->node.GROUP3.B2R2_SBA = addr; + break; + case 2: + b2r2_log_info(cont->dev, "2\n"); + node->node.GROUP4.B2R2_SBA = addr; + break; + case 3: + b2r2_log_info(cont->dev, "3\n"); + node->node.GROUP5.B2R2_SBA = addr; + break; + default: + BUG_ON(1); + break; + } + } + + b2r2_log_info(cont->dev, "%s: tba=%p\tsba=%p\n", __func__, + (void *)node->node.GROUP1.B2R2_TBA, + (void *)node->node.GROUP4.B2R2_SBA); + + node = node->next; + } + + return 0; +} + +/** + * b2r2_node_split_unassign_buffers() - releases temporary buffers + */ +void b2r2_node_split_unassign_buffers(struct b2r2_control *cont, + struct b2r2_node_split_job *this, struct b2r2_node *first) +{ + return; +} + +/** + * b2r2_node_split_cancel() - cancels and releases a job instance + */ +void b2r2_node_split_cancel(struct b2r2_control *cont, + struct b2r2_node_split_job *this) +{ + memset(this, 0, sizeof(*this)); + + return; +} + +/* + * Private functions + */ + +static void recalculate_rects(struct b2r2_control *cont, + struct b2r2_blt_req *req) +{ + struct b2r2_blt_rect new_dst_rect; + struct b2r2_blt_rect new_src_rect; + struct b2r2_blt_rect new_bg_rect; + + b2r2_trim_rects(cont, + req, &new_bg_rect, &new_dst_rect, &new_src_rect); + + req->dst_rect = new_dst_rect; + req->src_rect = new_src_rect; + req->bg_rect = new_bg_rect; +} + +static int check_rect(struct b2r2_control *cont, + const struct b2r2_blt_img *img, + const struct b2r2_blt_rect *rect, + const struct b2r2_blt_rect *clip) +{ + int ret; + + s32 l, r, b, t; + + /* Check rectangle dimensions*/ + if ((rect->width <= 0) || (rect->height <= 0)) { + b2r2_log_warn(cont->dev, "%s: Illegal rect (%d, %d, %d, %d)\n", + __func__, rect->x, rect->y, rect->width, + rect->height); + ret = -EINVAL; + goto error; + } + + /* If we are using clip we should only look at the intersection of the + rects */ + if (clip) { + l = MAX(rect->x, clip->x); + t = MAX(rect->y, clip->y); + r = MIN(rect->x + rect->width, clip->x + clip->width); + b = MIN(rect->y + rect->height, clip->y + clip->height); + } else { + l = rect->x; + t = rect->y; + r = rect->x + rect->width; + b = rect->y + rect->height; + } + + /* Check so that the rect isn't outside the buffer */ + if ((l < 0) || (t < 0) || (l >= img->width) || (t >= img->height)) { + b2r2_log_warn(cont->dev, "%s: rect origin outside buffer\n", + __func__); + ret = -EINVAL; + goto error; + } + + if ((r > img->width) || (b > img->height)) { + b2r2_log_warn(cont->dev, "%s: rect ends outside buffer\n", + __func__); + ret = -EINVAL; + goto error; + } + + /* Check so the intersected rectangle isn't empty */ + if ((l == r) || (t == b)) { + b2r2_log_warn(cont->dev, + "%s: rect is empty (width or height zero)\n", + __func__); + ret = -EINVAL; + goto error; + } + + return 0; +error: + b2r2_log_warn(cont->dev, "%s: Exit...\n", __func__); + return ret; +} + +/** + * bg_format_require_ivmx() + * + * Check if there are any color space conversion needed for the + * background to the destination format. + */ +static bool bg_format_require_ivmx(enum b2r2_blt_fmt bg_fmt, + enum b2r2_blt_fmt dst_fmt) +{ + if (is_rgb_fmt(bg_fmt)) { + if (is_yvu_fmt(dst_fmt)) + return true; + else if (dst_fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + dst_fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 || + dst_fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + dst_fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) + return true; + else if (is_yuv_fmt(dst_fmt)) + return true; + else if (is_bgr_fmt(dst_fmt)) + return true; + } else if (is_yvu_fmt(bg_fmt)) { + if (is_rgb_fmt(dst_fmt)) + return true; + else if (is_bgr_fmt(dst_fmt)) + return true; + else if (dst_fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + dst_fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 || + dst_fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + dst_fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) + return true; + else if (is_yuv_fmt(dst_fmt) && + !is_yvu_fmt(dst_fmt)) + return true; + } else if (bg_fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + bg_fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 || + bg_fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + bg_fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) { + if (is_rgb_fmt(dst_fmt)) { + return true; + } else if (is_yvu_fmt(dst_fmt)) { + return true; + } else if (is_yuv_fmt(dst_fmt)) { + switch (dst_fmt) { + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + break; + default: + return true; + } + } + } else if (is_yuv_fmt(bg_fmt)) { + if (is_rgb_fmt(dst_fmt)) + return true; + else if (is_bgr_fmt(dst_fmt)) + return true; + else if (dst_fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + dst_fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 || + dst_fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + dst_fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) + return true; + else if (is_yvu_fmt(dst_fmt)) + return true; + } else if (is_bgr_fmt(bg_fmt)) { + if (is_rgb_fmt(dst_fmt)) + return true; + else if (is_yvu_fmt(dst_fmt)) + return true; + else if (dst_fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + dst_fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 || + dst_fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + dst_fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) + return true; + else if (is_yuv_fmt(dst_fmt)) + return true; + } + + return false; +} + +/** + * analyze_fmt_conv() - analyze the format conversions needed for a job + */ +static int analyze_fmt_conv(struct b2r2_control *cont, + struct b2r2_node_split_buf *src, + struct b2r2_node_split_buf *dst, + const u32 **vmx, u32 *node_count) +{ + if (is_rgb_fmt(src->fmt)) { + if (is_yvu_fmt(dst->fmt)) + *vmx = &vmx_rgb_to_yvu[0]; + else if (dst->fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + dst->fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 || + dst->fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + dst->fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) + /* + * (A)YUV/VUY(A) formats differ only in component + * order. This is handled by the endianness bit + * in B2R2_STY/TTY registers when src/target are set. + */ + *vmx = &vmx_rgb_to_blt_yuv888[0]; + else if (is_yuv_fmt(dst->fmt)) + *vmx = &vmx_rgb_to_yuv[0]; + else if (is_bgr_fmt(dst->fmt)) + *vmx = &vmx_rgb_to_bgr[0]; + } else if (is_yvu_fmt(src->fmt)) { + if (is_rgb_fmt(dst->fmt)) + *vmx = &vmx_yvu_to_rgb[0]; + else if (is_bgr_fmt(dst->fmt)) + *vmx = &vmx_yvu_to_bgr[0]; + else if (dst->fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + dst->fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 || + dst->fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + dst->fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) + *vmx = &vmx_yvu_to_blt_yuv888[0]; + else if (is_yuv_fmt(dst->fmt) && + !is_yvu_fmt(dst->fmt)) + *vmx = &vmx_yvu_to_yuv[0]; + } else if (src->fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + src->fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 || + src->fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + src->fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) { + /* + * (A)YUV/VUY(A) formats differ only in component + * order. This is handled by the endianness bit + * in B2R2_STY/TTY registers when src/target are set. + */ + if (is_rgb_fmt(dst->fmt)) { + *vmx = &vmx_blt_yuv888_to_rgb[0]; + } else if (is_yvu_fmt(dst->fmt)) { + *vmx = &vmx_blt_yuv888_to_yvu[0]; + } else if (is_yuv_fmt(dst->fmt)) { + switch (dst->fmt) { + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: /* do nothing */ + break; + default: + *vmx = &vmx_blt_yuv888_to_yuv[0]; + break; + } + } + } else if (is_yuv_fmt(src->fmt)) { + if (is_rgb_fmt(dst->fmt)) + *vmx = &vmx_yuv_to_rgb[0]; + else if (is_bgr_fmt(dst->fmt)) + *vmx = &vmx_yuv_to_bgr[0]; + else if (dst->fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + dst->fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 || + dst->fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + dst->fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) + *vmx = &vmx_yuv_to_blt_yuv888[0]; + else if (is_yvu_fmt(dst->fmt)) + *vmx = &vmx_yvu_to_yuv[0]; + } else if (is_bgr_fmt(src->fmt)) { + if (is_rgb_fmt(dst->fmt)) + *vmx = &vmx_rgb_to_bgr[0]; + else if (is_yvu_fmt(dst->fmt)) + *vmx = &vmx_bgr_to_yvu[0]; + else if (dst->fmt == B2R2_BLT_FMT_24_BIT_YUV888 || + dst->fmt == B2R2_BLT_FMT_32_BIT_AYUV8888 || + dst->fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + dst->fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) + BUG_ON(1); + else if (is_yuv_fmt(dst->fmt)) + *vmx = &vmx_bgr_to_yuv[0]; + } + + if (dst->type == B2R2_FMT_TYPE_RASTER) { + *node_count = 1; + } else if (dst->type == B2R2_FMT_TYPE_SEMI_PLANAR) { + *node_count = 2; + } else if (dst->type == B2R2_FMT_TYPE_PLANAR) { + *node_count = 3; + } else { + /* That's strange... */ + BUG_ON(1); + } + + return 0; +} + +/** + * analyze_color_fill() - analyze a color fill operation + */ +static int analyze_color_fill(struct b2r2_node_split_job *this, + const struct b2r2_blt_request *req, u32 *node_count) +{ + int ret; + struct b2r2_control *cont = req->instance->control; + + /* Destination must be raster for raw fill to work */ + if (this->dst.type != B2R2_FMT_TYPE_RASTER) { + b2r2_log_warn(cont->dev, + "%s: fill requires raster destination\n", + __func__); + ret = -EINVAL; + goto error; + } + + /* We will try to fill the entire rectangle in one go */ + memcpy(&this->dst.win, &this->dst.rect, sizeof(this->dst.win)); + + /* Check if this is a direct fill */ + if ((!this->blend) && ((this->flags & B2R2_BLT_FLAG_SOURCE_FILL_RAW) || + (this->dst.fmt == B2R2_BLT_FMT_32_BIT_ARGB8888) || + (this->dst.fmt == B2R2_BLT_FMT_32_BIT_ABGR8888) || + (this->dst.fmt == B2R2_BLT_FMT_32_BIT_AYUV8888) || + (this->dst.fmt == B2R2_BLT_FMT_32_BIT_VUYA8888))) { + this->type = B2R2_DIRECT_FILL; + + /* The color format will be the same as the dst fmt */ + this->src.fmt = this->dst.fmt; + + /* The entire destination rectangle will be */ + memcpy(&this->dst.win, &this->dst.rect, + sizeof(this->dst.win)); + *node_count = 1; + } else { + this->type = B2R2_FILL; + + /* Determine the fill color format */ + if (this->flags & B2R2_BLT_FLAG_SOURCE_FILL_RAW) { + /* The color format will be the same as the dst fmt */ + this->src.fmt = this->dst.fmt; + } else { + /* If the dst fmt is YUV the fill fmt will be as well */ + if (is_yuv_fmt(this->dst.fmt)) { + this->src.fmt = B2R2_BLT_FMT_32_BIT_AYUV8888; + } else if (is_rgb_fmt(this->dst.fmt)) { + this->src.fmt = B2R2_BLT_FMT_32_BIT_ARGB8888; + } else if (is_bgr_fmt(this->dst.fmt)) { + /* Color will still be ARGB, we will translate + using IVMX (configured later) */ + this->src.fmt = B2R2_BLT_FMT_32_BIT_ARGB8888; + } else { + /* Wait, what? */ + b2r2_log_warn(cont->dev, "%s: " + "Illegal destination format for fill", + __func__); + ret = -EINVAL; + goto error; + } + } + + /* Also, B2R2 seems to ignore the pixel alpha value */ + if (((this->flags & B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND) + != 0) && + ((this->flags & B2R2_BLT_FLAG_SOURCE_FILL_RAW) + == 0) && fmt_has_alpha(this->src.fmt)) { + u8 pixel_alpha = get_alpha(this->src.fmt, + this->src.color); + u32 new_global = pixel_alpha * this->global_alpha / 255; + + this->global_alpha = (u8)new_global; + + /* Set the pixel alpha to full opaque so we don't get + any nasty surprises */ + this->src.color = set_alpha(this->src.fmt, 0xFF, + this->src.color); + } + + ret = analyze_fmt_conv( + cont, &this->src, &this->dst, &this->ivmx, + node_count); + if (ret < 0) + goto error; + } + + return 0; + +error: + b2r2_log_warn(cont->dev, "%s: Exit...\n", __func__); + return ret; + +} + +/** + * analyze_transform() - analyze a transform operation (rescale, rotate, etc.) + */ +static int analyze_transform(struct b2r2_node_split_job *this, + const struct b2r2_blt_request *req, u32 *node_count, + u32 *buf_count) +{ + int ret; + bool is_scaling; +#ifdef CONFIG_B2R2_DEBUG + struct b2r2_control *cont = req->instance->control; +#endif + + b2r2_log_info(cont->dev, "%s\n", __func__); + + /* + * The transform enum is defined so that all rotation transforms are + * masked with the rotation flag + */ + this->rotation = (this->transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) != 0; + + /* B2R2 cannot do rotations if the destination is not raster, or 422R */ + if (this->rotation && (this->dst.type != B2R2_FMT_TYPE_RASTER || + this->dst.fmt == B2R2_BLT_FMT_Y_CB_Y_CR || + this->dst.fmt == B2R2_BLT_FMT_CB_Y_CR_Y)) { + b2r2_log_warn(cont->dev, + "%s: Unsupported operation " + "(rot && (!dst_raster || dst==422R))", + __func__); + ret = -ENOSYS; + goto unsupported; + } + + /* Flip the image by changing the scan order of the destination */ + if (this->transform & B2R2_BLT_TRANSFORM_FLIP_H) + this->dst.hso = B2R2_TY_HSO_RIGHT_TO_LEFT; + if (this->transform & B2R2_BLT_TRANSFORM_FLIP_V) + this->dst.vso = B2R2_TY_VSO_BOTTOM_TO_TOP; + + /* Check for scaling */ + if (this->rotation) { + is_scaling = (this->src.rect.width != this->dst.rect.height) || + (this->src.rect.height != this->dst.rect.width); + } else { + is_scaling = (this->src.rect.width != this->dst.rect.width) || + (this->src.rect.height != this->dst.rect.height); + } + + /* Plane separated formats must be treated as scaling */ + is_scaling = is_scaling || + (this->src.type == B2R2_FMT_TYPE_SEMI_PLANAR) || + (this->src.type == B2R2_FMT_TYPE_PLANAR) || + (this->dst.type == B2R2_FMT_TYPE_SEMI_PLANAR) || + (this->dst.type == B2R2_FMT_TYPE_PLANAR); + + if (is_scaling && this->rotation && this->blend) { + /* TODO: This is unsupported. Fix it! */ + b2r2_log_info(cont->dev, "%s: Unsupported operation " + "(rot+rescale+blend)\n", __func__); + ret = -ENOSYS; + goto unsupported; + } + + /* Check which type of transform */ + if (is_scaling && this->rotation) { + ret = analyze_rot_scale(this, req, node_count, buf_count); + if (ret < 0) + goto error; + } else if (is_scaling) { + ret = analyze_scaling(this, req, node_count, buf_count); + if (ret < 0) + goto error; + } else if (this->rotation) { + ret = analyze_rotate(this, req, node_count, buf_count); + if (ret < 0) + goto error; + } else { + /* No additional nodes needed for a flip */ + ret = analyze_copy(this, req, node_count, buf_count); + if (ret < 0) + goto error; + this->type = B2R2_FLIP; + } + + return 0; + +error: + b2r2_log_warn(cont->dev, "%s: error!\n", __func__); +unsupported: + return ret; +} + +/** + * analyze_copy() - analyze a copy operation + */ +static int analyze_copy(struct b2r2_node_split_job *this, + const struct b2r2_blt_request *req, u32 *node_count, + u32 *buf_count) +{ + int ret; + struct b2r2_control *cont = req->instance->control; + + memcpy(&this->dst.win, &this->dst.rect, sizeof(this->dst.win)); + + if (!this->blend && + !(this->flags & B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) && + (this->src.fmt == this->dst.fmt) && + (this->src.type == B2R2_FMT_TYPE_RASTER) && + (this->dst.rect.x >= this->clip_rect.x) && + (this->dst.rect.y >= this->clip_rect.y) && + (this->dst.rect.x + this->dst.rect.width <= + this->clip_rect.x + this->clip_rect.width) && + (this->dst.rect.y + this->dst.rect.height <= + this->clip_rect.y + this->clip_rect.height)) { + this->type = B2R2_DIRECT_COPY; + *node_count = 1; + } else { + u32 copy_count; + + this->type = B2R2_COPY; + + ret = analyze_fmt_conv(cont, &this->src, &this->dst, + &this->ivmx, ©_count); + if (ret < 0) + goto error; + + *node_count = copy_count; + } + + return 0; + +error: + b2r2_log_warn(cont->dev, "%s: Exit...\n", __func__); + return ret; +} + +static int calc_rot_count(u32 width, u32 height) +{ + int count; + + count = width / B2R2_ROTATE_MAX_WIDTH; + if (width % B2R2_ROTATE_MAX_WIDTH) + count++; + if (height > B2R2_ROTATE_MAX_WIDTH && + height % B2R2_ROTATE_MAX_WIDTH) + count *= 2; + + return count; +} + +static int analyze_rot_scale_downscale(struct b2r2_node_split_job *this, + const struct b2r2_blt_request *req, u32 *node_count, + u32 *buf_count) +{ + int ret; + struct b2r2_control *cont = req->instance->control; + struct b2r2_node_split_buf *src = &this->src; + struct b2r2_node_split_buf *dst = &this->dst; + struct b2r2_node_split_buf *tmp = &this->tmp_bufs[0]; + + u32 num_rows; + u32 num_cols; + u32 rot_count; + u32 rescale_count; + u32 nodes_per_rot; + u32 nodes_per_rescale; + u32 right_width; + u32 bottom_height; + const u32 *dummy_vmx; + + b2r2_log_info(cont->dev, "%s\n", __func__); + + /* Calculate the desired tmp buffer size */ + tmp->win.width = rescale(cont, B2R2_RESCALE_MAX_WIDTH - 1, this->h_rsf); + tmp->win.width >>= 10; + tmp->win.width = min(tmp->win.width, dst->rect.height); + tmp->win.height = dst->rect.width; + + setup_tmp_buf(cont, tmp, this->max_buf_size, dst->fmt, tmp->win.width, + tmp->win.height); + tmp->tmp_buf_index = 1; + this->work_bufs[0].size = tmp->pitch * tmp->height; + + tmp->win.width = tmp->rect.width; + tmp->win.height = tmp->rect.height; + + tmp->dither = dst->dither; + dst->dither = 0; + + /* Update the dst window with the actual tmp buffer dimensions */ + dst->win.width = tmp->win.height; + dst->win.height = tmp->win.width; + + /* The rotated stripes are written to the destination bottom-up */ + if (this->dst.vso == B2R2_TY_VSO_TOP_TO_BOTTOM) + this->dst.vso = B2R2_TY_VSO_BOTTOM_TO_TOP; + else + this->dst.vso = B2R2_TY_VSO_TOP_TO_BOTTOM; + + /* + * Calculate how many nodes are required to copy to and from the tmp + * buffer + */ + ret = analyze_fmt_conv(cont, src, tmp, &this->ivmx, &nodes_per_rescale); + if (ret < 0) + goto error; + + /* We will not do any format conversion in the rotation stage */ + ret = analyze_fmt_conv(cont, tmp, dst, &dummy_vmx, &nodes_per_rot); + if (ret < 0) + goto error; + + /* Calculate node count for the inner tiles */ + num_cols = dst->rect.width / dst->win.width; + num_rows = dst->rect.height / dst->win.height; + + rescale_count = num_cols * num_rows; + rot_count = calc_rot_count(dst->win.height, dst->win.width) * + num_cols * num_rows; + + right_width = dst->rect.width % dst->win.width; + bottom_height = dst->rect.height % dst->win.height; + + /* Calculate node count for the rightmost tiles */ + if (right_width) { + u32 count = calc_rot_count(dst->win.height, right_width); + + rot_count += count * num_rows; + rescale_count += num_rows; + b2r2_log_info(cont->dev, "%s: rightmost: %d nodes\n", __func__, + count*num_rows); + } + + /* Calculate node count for the bottom tiles */ + if (bottom_height) { + u32 count = calc_rot_count(bottom_height, dst->win.width); + + rot_count += count * num_cols; + rescale_count += num_cols; + b2r2_log_info(cont->dev, "%s: bottom: %d nodes\n", __func__, + count * num_cols); + + } + + /* And finally for the bottom right corner */ + if (right_width && bottom_height) { + u32 count = calc_rot_count(bottom_height, right_width); + + rot_count += count; + rescale_count++; + b2r2_log_info(cont->dev, "%s: bottom right: %d nodes\n", + __func__, count); + + } + + *node_count = rot_count * nodes_per_rot; + *node_count += rescale_count * nodes_per_rescale; + *buf_count = 1; + + return 0; + +error: + b2r2_log_warn(cont->dev, "%s: error!\n", __func__); + return ret; +} + +static int analyze_rot_scale_upscale(struct b2r2_node_split_job *this, + const struct b2r2_blt_request *req, u32 *node_count, + u32 *buf_count) +{ + /* TODO: When upscaling we should optimally to the rotation first... */ + return analyze_rot_scale_downscale(this, req, node_count, buf_count); +} + +/** + * analyze_rot_scaling() - analyzes a combined rotation and scaling op + */ +static int analyze_rot_scale(struct b2r2_node_split_job *this, + const struct b2r2_blt_request *req, u32 *node_count, + u32 *buf_count) +{ + int ret; + bool upscale; + struct b2r2_control *cont = req->instance->control; + + ret = analyze_scale_factors(cont, this); + if (ret < 0) + goto error; + + upscale = (u32)this->h_rsf * (u32)this->v_rsf < (1 << 20); + + if (upscale) + ret = analyze_rot_scale_upscale(this, req, node_count, + buf_count); + else + ret = analyze_rot_scale_downscale(this, req, node_count, + buf_count); + + if (ret < 0) + goto error; + + this->type = B2R2_SCALE_AND_ROTATE; + + return 0; + +error: + return ret; +} + +/** + * analyze_scaling() - analyze a rescale operation + */ +static int analyze_scaling(struct b2r2_node_split_job *this, + const struct b2r2_blt_request *req, u32 *node_count, + u32 *buf_count) +{ + int ret; + u32 copy_count; + u32 nbr_cols; + s32 dst_w; + struct b2r2_control *cont = req->instance->control; + + b2r2_log_info(cont->dev, "%s\n", __func__); + + ret = analyze_scale_factors(cont, this); + if (ret < 0) + goto error; + + /* Find out how many nodes a simple copy would require */ + ret = analyze_fmt_conv(cont, &this->src, &this->dst, &this->ivmx, + ©_count); + if (ret < 0) + goto error; + + memcpy(&this->dst.win, &this->dst.rect, sizeof(this->dst.win)); + + /* + * We need to subtract from the actual maximum rescale width since the + * start of the stripe will be floored and the end ceiled. This could in + * some cases cause the stripe to be one pixel more than the maximum + * width. + * + * Example: + * x = 127.8, w = 127.8 + * + * The stripe will touch pixels 127.8 through 255.6, i.e. 129 pixels. + */ + dst_w = rescale(cont, B2R2_RESCALE_MAX_WIDTH - 1, this->h_rsf); + if (dst_w < (1 << 10)) + dst_w = 1; + else + dst_w >>= 10; + + b2r2_log_info(cont->dev, "%s: dst_w=%d dst.rect.width=%d\n", + __func__, dst_w, this->dst.rect.width); + + this->dst.win.width = min(dst_w, this->dst.rect.width); + + b2r2_log_info(cont->dev, "%s: dst.win.width=%d\n", + __func__, this->dst.win.width); + + nbr_cols = this->dst.rect.width / this->dst.win.width; + if (this->dst.rect.width % this->dst.win.width) + nbr_cols++; + + *node_count = copy_count * nbr_cols; + + this->type = B2R2_SCALE; + + b2r2_log_info(cont->dev, "%s exit\n", __func__); + + return 0; + +error: + b2r2_log_warn(cont->dev, "%s: Exit...\n", __func__); + return ret; + +} + +/** + * analyze_rotate() - analyze a rotate operation + */ +static int analyze_rotate(struct b2r2_node_split_job *this, + const struct b2r2_blt_request *req, u32 *node_count, + u32 *buf_count) +{ + int ret; + u32 nodes_per_tile; + struct b2r2_control *cont = req->instance->control; + + /* Find out how many nodes a simple copy would require */ + ret = analyze_fmt_conv(cont, &this->src, &this->dst, &this->ivmx, + &nodes_per_tile); + if (ret < 0) + goto error; + + this->type = B2R2_ROTATE; + + /* The rotated stripes are written to the destination bottom-up */ + if (this->dst.vso == B2R2_TY_VSO_TOP_TO_BOTTOM) + this->dst.vso = B2R2_TY_VSO_BOTTOM_TO_TOP; + else + this->dst.vso = B2R2_TY_VSO_TOP_TO_BOTTOM; + + memcpy(&this->dst.win, &this->dst.rect, sizeof(this->dst.win)); + + this->dst.win.height = min(this->dst.win.height, B2R2_ROTATE_MAX_WIDTH); + + /* + * B2R2 cannot do rotations on stripes that are not a multiple of 16 + * pixels high (if larger than 16 pixels). + */ + if (this->dst.win.width > 16) + this->dst.win.width -= (this->dst.win.width % 16); + + /* Blending cannot be combined with rotation */ + if (this->blend) { + struct b2r2_node_split_buf *tmp = &this->tmp_bufs[0]; + enum b2r2_blt_fmt tmp_fmt; + + if (is_yuv_fmt(this->dst.fmt)) + tmp_fmt = B2R2_BLT_FMT_32_BIT_AYUV8888; + else if (is_bgr_fmt(this->dst.fmt)) + tmp_fmt = B2R2_BLT_FMT_32_BIT_ABGR8888; + else + tmp_fmt = B2R2_BLT_FMT_32_BIT_ARGB8888; + + setup_tmp_buf(cont, tmp, this->max_buf_size, tmp_fmt, + this->dst.win.width, this->dst.win.height); + + tmp->tmp_buf_index = 1; + + tmp->vso = B2R2_TY_VSO_BOTTOM_TO_TOP; + + this->dst.win.width = tmp->rect.width; + this->dst.win.height = tmp->rect.height; + + memcpy(&tmp->win, &tmp->rect, sizeof(tmp->win)); + + *buf_count = 1; + this->work_bufs[0].size = tmp->pitch * tmp->height; + + /* + * One more node per tile is required to rotate to the temp + * buffer. + */ + nodes_per_tile++; + } + + /* Finally, calculate the node count */ + *node_count = nodes_per_tile * + calc_rot_count(this->src.rect.width, this->src.rect.height); + + return 0; + +error: + b2r2_log_warn(cont->dev, "%s: Exit...\n", __func__); + return ret; +} + +/** + * analyze_scale_factors() - determines the scale factors for the op + */ +static int analyze_scale_factors(struct b2r2_control *cont, + struct b2r2_node_split_job *this) +{ + int ret; + + u16 hsf; + u16 vsf; + + if (this->rotation) { + ret = calculate_scale_factor(cont, this->src.rect.width, + this->dst.rect.height, &hsf); + if (ret < 0) + goto error; + + ret = calculate_scale_factor(cont, this->src.rect.height, + this->dst.rect.width, &vsf); + if (ret < 0) + goto error; + } else { + ret = calculate_scale_factor(cont, this->src.rect.width, + this->dst.rect.width, &hsf); + if (ret < 0) + goto error; + + ret = calculate_scale_factor(cont, this->src.rect.height, + this->dst.rect.height, &vsf); + if (ret < 0) + goto error; + } + + this->h_rescale = hsf != (1 << 10); + this->v_rescale = vsf != (1 << 10); + + this->h_rsf = hsf; + this->v_rsf = vsf; + + b2r2_log_info(cont->dev, "%s: h_rsf=%.4x\n", __func__, this->h_rsf); + b2r2_log_info(cont->dev, "%s: v_rsf=%.4x\n", __func__, this->v_rsf); + + return 0; +error: + b2r2_log_warn(cont->dev, "%s: Exit...\n", __func__); + return ret; +} + +/** + * configure_tile() - configures one tile of a blit operation + */ +static int configure_tile(struct b2r2_control *cont, + struct b2r2_node_split_job *this, struct b2r2_node *node, + struct b2r2_node **next) +{ + int ret = 0; + + struct b2r2_node *last; + struct b2r2_node_split_buf *src = &this->src; + struct b2r2_node_split_buf *dst = &this->dst; + struct b2r2_node_split_buf *bg = &this->bg; + + struct b2r2_blt_rect dst_norm; + struct b2r2_blt_rect src_norm; + struct b2r2_blt_rect bg_norm; + + /* Normalize the dest coords to the dest rect coordinate space */ + dst_norm.x = dst->win.x - dst->rect.x; + dst_norm.y = dst->win.y - dst->rect.y; + dst_norm.width = dst->win.width; + dst_norm.height = dst->win.height; + + if (dst->vso == B2R2_TY_VSO_BOTTOM_TO_TOP) { + /* The y coord should be counted from the bottom */ + dst_norm.y = dst->rect.height - (dst_norm.y + 1); + } + if (dst->hso == B2R2_TY_HSO_RIGHT_TO_LEFT) { + /* The x coord should be counted from the right */ + dst_norm.x = dst->rect.width - (dst_norm.x + 1); + } + + /* If the destination is rotated we should swap x, y */ + if (this->rotation) { + src_norm.x = dst_norm.y; + src_norm.y = dst_norm.x; + src_norm.width = dst_norm.height; + src_norm.height = dst_norm.width; + } else { + src_norm.x = dst_norm.x; + src_norm.y = dst_norm.y; + src_norm.width = dst_norm.width; + src_norm.height = dst_norm.height; + } + + /* Convert to src coordinate space */ + src->win.x = src_norm.x + src->rect.x; + src->win.y = src_norm.y + src->rect.y; + src->win.width = src_norm.width; + src->win.height = src_norm.height; + + /* Set bg norm */ + bg_norm.x = dst->win.x - dst->rect.x; + bg_norm.y = dst->win.y - dst->rect.y; + bg_norm.width = dst->win.width; + bg_norm.height = dst->win.height; + + /* Convert to bg coordinate space */ + bg->win.x = bg_norm.x + bg->rect.x; + bg->win.y = bg_norm.y + bg->rect.y; + bg->win.width = bg_norm.width; + bg->win.height = bg_norm.height; + bg->vso = dst->vso; + bg->hso = dst->hso; + + /* Do the configuration depending on operation type */ + switch (this->type) { + case B2R2_DIRECT_FILL: + configure_direct_fill(cont, node, this->src.color, dst, &last); + break; + + case B2R2_DIRECT_COPY: + configure_direct_copy(cont, node, src, dst, &last); + break; + + case B2R2_FILL: + ret = configure_fill(cont, node, src->color, src->fmt, + dst, this->ivmx, &last); + break; + + case B2R2_FLIP: /* FLIP is just a copy with different VSO/HSO */ + case B2R2_COPY: + ret = configure_copy( + cont, node, src, dst, this->ivmx, &last, this); + break; + + case B2R2_ROTATE: + { + struct b2r2_node_split_buf *tmp = &this->tmp_bufs[0]; + + if (this->blend) { + b2r2_log_info(cont->dev, "%s: rotation + " + "blend\n", __func__); + + tmp->win.x = 0; + tmp->win.y = tmp->win.height - 1; + tmp->win.width = dst->win.width; + tmp->win.height = dst->win.height; + + /* Rotate to the temp buf */ + ret = configure_rotate(cont, node, src, tmp, + this->ivmx, &node, NULL); + if (ret < 0) + goto error; + + /* Then do a copy to the destination */ + ret = configure_copy(cont, node, tmp, dst, NULL, + &last, this); + } else { + /* Just do a rotation */ + ret = configure_rotate(cont, node, src, dst, + this->ivmx, &last, this); + } + } + break; + + case B2R2_SCALE: + ret = configure_scale(cont, node, src, dst, this->h_rsf, + this->v_rsf, this->ivmx, &last, this); + break; + + case B2R2_SCALE_AND_ROTATE: + ret = configure_rot_scale(cont, this, node, &last); + break; + + default: + b2r2_log_warn(cont->dev, "%s: Unsupported request\n", __func__); + ret = -ENOSYS; + goto error; + break; + + } + + if (ret < 0) + goto error; + + /* Scale and rotate will configure its own blending and clipping */ + if (this->type != B2R2_SCALE_AND_ROTATE) { + + /* Configure blending and clipping */ + do { + if (node == NULL) { + b2r2_log_warn(cont->dev, "%s: " + "Internal error! Out of nodes!\n", + __func__); + ret = -ENOMEM; + goto error; + } + + if (this->blend) { + if (this->flags & B2R2_BLT_FLAG_BG_BLEND) + configure_bg(cont, node, bg, + this->swap_fg_bg); + else + configure_bg(cont, node, dst, + this->swap_fg_bg); + configure_blend(cont, node, this->flags, + this->global_alpha); + } + if (this->clip) + configure_clip(cont, node, &this->clip_rect); + + node = node->next; + + } while (node != last); + } + + /* Consume the nodes */ + *next = last; + + return 0; + +error: + b2r2_log_warn(cont->dev, "%s: Error!\n", __func__); + return ret; +} + +/* + * configure_sub_rot() - configure a sub-rotation + * + * This functions configures a set of nodes for rotation using the destination + * window instead of the rectangle for calculating tiles. + */ +static int configure_sub_rot(struct b2r2_control *cont, + struct b2r2_node *node, + struct b2r2_node_split_buf *src, + struct b2r2_node_split_buf *dst, + const u32 *ivmx, struct b2r2_node **next, + struct b2r2_node_split_job *job) +{ + int ret; + + struct b2r2_blt_rect src_win; + struct b2r2_blt_rect dst_win; + + u32 y_pixels = 0; + u32 x_pixels = 0; + + memcpy(&src_win, &src->win, sizeof(src_win)); + memcpy(&dst_win, &dst->win, sizeof(dst_win)); + + b2r2_log_info(cont->dev, "%s: src_win=(%d, %d, %d, %d) " + "dst_win=(%d, %d, %d, %d)\n", __func__, + src_win.x, src_win.y, src_win.width, src_win.height, + dst_win.x, dst_win.y, dst_win.width, dst_win.height); + + dst->win.height = B2R2_ROTATE_MAX_WIDTH; + if (dst->win.width % B2R2_ROTATE_MAX_WIDTH) + dst->win.width -= dst->win.width % B2R2_ROTATE_MAX_WIDTH; + + while (x_pixels < dst_win.width) { + u32 src_x = src->win.x; + u32 src_w = src->win.width; + u32 dst_y = dst->win.y; + u32 dst_h = dst->win.height; + + dst->win.width = min(dst->win.width, dst_win.width - + (int)x_pixels); + src->win.height = dst->win.width; + + b2r2_log_info(cont->dev, "%s: x_pixels=%d\n", + __func__, x_pixels); + + while (y_pixels < dst_win.height) { + dst->win.height = min(dst->win.height, + dst_win.height - (int)y_pixels); + src->win.width = dst->win.height; + + b2r2_log_info(cont->dev, "%s: y_pixels=%d\n", + __func__, y_pixels); + + ret = configure_rotate(cont, node, src, dst, + ivmx, &node, job); + if (ret < 0) + goto error; + + src->win.x += (src->hso == B2R2_TY_HSO_LEFT_TO_RIGHT) ? + src->win.width : -src->win.width; + dst->win.y += (dst->vso == B2R2_TY_VSO_TOP_TO_BOTTOM) ? + dst->win.height : -dst->win.height; + + y_pixels += dst->win.height; + } + + src->win.x = src_x; + src->win.y += (src->vso == B2R2_TY_VSO_TOP_TO_BOTTOM) ? + src->win.height : -src->win.height; + src->win.width = src_w; + + dst->win.x += (dst->hso == B2R2_TY_HSO_LEFT_TO_RIGHT) ? + dst->win.width : -dst->win.width; + dst->win.y = dst_y; + dst->win.height = dst_h; + + x_pixels += dst->win.width; + y_pixels = 0; + + } + + memcpy(&src->win, &src_win, sizeof(src->win)); + memcpy(&dst->win, &dst_win, sizeof(dst->win)); + + *next = node; + + return 0; + +error: + b2r2_log_warn(cont->dev, "%s: error!\n", __func__); + return ret; +} + +/** + * configure_rot_downscale() - configures a combined rotate and downscale + * + * When doing a downscale it is better to do the rotation last. + */ +static int configure_rot_downscale(struct b2r2_control *cont, + struct b2r2_node_split_job *this, + struct b2r2_node *node, struct b2r2_node **next) +{ + int ret; + + struct b2r2_node_split_buf *src = &this->src; + struct b2r2_node_split_buf *dst = &this->dst; + struct b2r2_node_split_buf *tmp = &this->tmp_bufs[0]; + + tmp->win.x = 0; + tmp->win.y = 0; + tmp->win.width = dst->win.height; + tmp->win.height = dst->win.width; + + ret = configure_scale(cont, node, src, tmp, this->h_rsf, this->v_rsf, + this->ivmx, &node, this); + if (ret < 0) + goto error; + + ret = configure_sub_rot(cont, node, tmp, dst, NULL, &node, this); + if (ret < 0) + goto error; + + *next = node; + + return 0; + +error: + b2r2_log_info(cont->dev, "%s: error!\n", __func__); + return ret; +} + +/** + * configure_rot_upscale() - configures a combined rotate and upscale + * + * When doing an upscale it is better to do the rotation first. + */ +static int configure_rot_upscale(struct b2r2_control *cont, + struct b2r2_node_split_job *this, struct b2r2_node *node, + struct b2r2_node **next) +{ + /* TODO: Implement a optimal upscale (rotation first) */ + return configure_rot_downscale(cont, this, node, next); +} + +/** + * configure_rot_scale() - configures a combined rotation and scaling op + */ +static int configure_rot_scale(struct b2r2_control *cont, + struct b2r2_node_split_job *this, struct b2r2_node *node, + struct b2r2_node **next) +{ + int ret; + + bool upscale = (u32)this->h_rsf * (u32)this->v_rsf < (1 << 10); + + if (upscale) + ret = configure_rot_upscale(cont, this, node, next); + else + ret = configure_rot_downscale(cont, this, node, next); + + if (ret < 0) + goto error; + + return 0; + +error: + b2r2_log_warn(cont->dev, "%s: error!\n", __func__); + return ret; +} + +/** + * configure_direct_fill() - configures the given node for direct fill + * + * @node - the node to configure + * @color - the fill color + * @dst - the destination buffer + * @next - the next empty node in the node list + * + * This operation will always consume one node only. + */ +static void configure_direct_fill( + struct b2r2_control *cont, + struct b2r2_node *node, + u32 color, + struct b2r2_node_split_buf *dst, + struct b2r2_node **next) +{ + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_COLOR_FILL | B2R2_CIC_SOURCE_1; + node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_1_DIRECT_FILL; + + /* Target setup */ + set_target(node, dst->addr, dst); + + /* Source setup */ + + /* It seems B2R2 checks so that source and dest has the same format */ + node->node.GROUP3.B2R2_STY = to_native_fmt(dst->fmt); + node->node.GROUP2.B2R2_S1CF = color; + node->node.GROUP2.B2R2_S2CF = 0; + + /* Consume the node */ + *next = node->next; +} + +/** + * configure_direct_copy() - configures the node for direct copy + * + * @node - the node to configure + * @src - the source buffer + * @dst - the destination buffer + * @next - the next empty node in the node list + * + * This operation will always consume one node only. + */ +static void configure_direct_copy( + struct b2r2_control *cont, + struct b2r2_node *node, + struct b2r2_node_split_buf *src, + struct b2r2_node_split_buf *dst, + struct b2r2_node **next) +{ + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_1; + node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_1_DIRECT_COPY; + + /* Source setup, use the base function to avoid altering the INS */ + set_src(&node->node.GROUP3, src->addr, src); + + /* Target setup */ + set_target(node, dst->addr, dst); + + /* Consume the node */ + *next = node->next; +} + +/** + * configure_fill() - configures the given node for color fill + * + * @node - the node to configure + * @color - the fill color + * @fmt - the source color format + * @dst - the destination buffer + * @next - the next empty node in the node list + * + * A normal fill operation can be combined with any other per pixel operations + * such as blend. + * + * This operation will consume as many nodes as are required to write to the + * destination format. + */ +static int configure_fill( + struct b2r2_control *cont, + struct b2r2_node *node, + u32 color, + enum b2r2_blt_fmt fmt, + struct b2r2_node_split_buf *dst, + const u32 *ivmx, + struct b2r2_node **next) +{ + int ret; + struct b2r2_node *last; + + /* Configure the destination */ + ret = configure_dst(cont, node, dst, ivmx, &last); + if (ret < 0) + goto error; + + do { + if (node == NULL) { + b2r2_log_warn(cont->dev, "%s: " + "Internal error! Out of nodes!\n", __func__); + ret = -ENOMEM; + goto error; + } + + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2 | + B2R2_CIC_COLOR_FILL; + node->node.GROUP0.B2R2_INS |= + B2R2_INS_SOURCE_2_COLOR_FILL_REGISTER; + node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BYPASS_S2_S3; + + /* B2R2 has a bug that disables color fill from S2. As a + workaround we use S1 for the color. */ + node->node.GROUP2.B2R2_S1CF = 0; + node->node.GROUP2.B2R2_S2CF = color; + + /* TO BE REMOVED: */ + set_src_2(node, dst->addr, dst); + node->node.GROUP4.B2R2_STY = to_native_fmt(fmt); + + /* Setup the iVMX for color conversion */ + if (ivmx != NULL) + set_ivmx(node, ivmx); + + if ((dst->type == B2R2_FMT_TYPE_PLANAR) || + (dst->type == B2R2_FMT_TYPE_SEMI_PLANAR)) { + + node->node.GROUP0.B2R2_INS |= + B2R2_INS_RESCALE2D_ENABLED; + node->node.GROUP8.B2R2_FCTL = + B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER | + B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER | + B2R2_FCTL_LUMA_HF2D_MODE_ENABLE_RESIZER | + B2R2_FCTL_LUMA_VF2D_MODE_ENABLE_RESIZER; + node->node.GROUP9.B2R2_RSF = + (1 << (B2R2_RSF_HSRC_INC_SHIFT + 10)) | + (1 << (B2R2_RSF_VSRC_INC_SHIFT + 10)); + node->node.GROUP9.B2R2_RZI = + B2R2_RZI_DEFAULT_HNB_REPEAT | + (2 << B2R2_RZI_VNB_REPEAT_SHIFT); + + node->node.GROUP10.B2R2_RSF = + (1 << (B2R2_RSF_HSRC_INC_SHIFT + 10)) | + (1 << (B2R2_RSF_VSRC_INC_SHIFT + 10)); + node->node.GROUP10.B2R2_RZI = + B2R2_RZI_DEFAULT_HNB_REPEAT | + (2 << B2R2_RZI_VNB_REPEAT_SHIFT); + } + + node = node->next; + + } while (node != last); + + /* Consume the nodes */ + *next = node; + + return 0; +error: + b2r2_log_warn(cont->dev, "%s: Exit...\n", __func__); + return ret; +} + +/** + * configure_copy() - configures the given node for a copy operation + * + * @node - the node to configure + * @src - the source buffer + * @dst - the destination buffer + * @ivmx - the iVMX to use for color conversion + * @next - the next empty node in the node list + * + * This operation will consume as many nodes as are required to write to the + * destination format. + */ +static int configure_copy( + struct b2r2_control *cont, + struct b2r2_node *node, + struct b2r2_node_split_buf *src, + struct b2r2_node_split_buf *dst, + const u32 *ivmx, + struct b2r2_node **next, + struct b2r2_node_split_job *this) +{ + int ret; + + struct b2r2_node *last; + + ret = configure_dst(cont, node, dst, ivmx, &last); + if (ret < 0) + goto error; + + /* Configure the source for each node */ + do { + if (node == NULL) { + b2r2_log_warn(cont->dev, "%s: " + " Internal error! Out of nodes!\n", + __func__); + ret = -ENOMEM; + goto error; + } + + node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BYPASS_S2_S3; + if (this != NULL && + (this->flags & B2R2_BLT_FLAG_SOURCE_COLOR_KEY) + != 0) { + u32 key_color = 0; + + node->node.GROUP0.B2R2_ACK |= + B2R2_ACK_CKEY_SEL_SRC_AFTER_CLUT | + B2R2_ACK_CKEY_RED_MATCH_IF_BETWEEN | + B2R2_ACK_CKEY_GREEN_MATCH_IF_BETWEEN | + B2R2_ACK_CKEY_BLUE_MATCH_IF_BETWEEN; + node->node.GROUP0.B2R2_INS |= B2R2_INS_CKEY_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_COLOR_KEY; + + key_color = to_RGB888(this->flag_param, src->fmt); + node->node.GROUP12.B2R2_KEY1 = key_color; + node->node.GROUP12.B2R2_KEY2 = key_color; + } + + if (this != NULL && + (this->flags & + B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) != 0) { + struct b2r2_blt_request *request = + container_of(this, struct b2r2_blt_request, + node_split_job); + node->node.GROUP0.B2R2_INS |= B2R2_INS_CLUTOP_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_CLUT; + node->node.GROUP7.B2R2_CCO = + B2R2_CCO_CLUT_COLOR_CORRECTION | + B2R2_CCO_CLUT_UPDATE; + node->node.GROUP7.B2R2_CML = request->clut_phys_addr; + } + /* Configure the source(s) */ + configure_src(cont, node, src, ivmx); + + node = node->next; + } while (node != last); + + /* Consume the nodes */ + *next = node; + + return 0; +error: + b2r2_log_warn(cont->dev, "%s: Exit...\n", __func__); + return ret; +} + +/** + * configure_rotate() - configures the given node for rotation + * + * @node - the node to configure + * @src - the source buffer + * @dst - the destination buffer + * @ivmx - the iVMX to use for color conversion + * @next - the next empty node in the node list + * + * This operation will consume as many nodes are are required by the combination + * of rotating and writing the destination format. + */ +static int configure_rotate( + struct b2r2_control *cont, + struct b2r2_node *node, + struct b2r2_node_split_buf *src, + struct b2r2_node_split_buf *dst, + const u32 *ivmx, + struct b2r2_node **next, + struct b2r2_node_split_job *this) +{ + int ret; + + struct b2r2_node *last; + + ret = configure_copy(cont, node, src, dst, ivmx, &last, this); + if (ret < 0) + goto error; + + do { + if (node == NULL) { + b2r2_log_warn(cont->dev, "%s: " + "Internal error! Out of nodes!\n", + __func__); + ret = -ENOMEM; + goto error; + } + + node->node.GROUP0.B2R2_INS |= B2R2_INS_ROTATION_ENABLED; + + b2r2_log_debug(cont->dev, "%s:\n" + "\tB2R2_TXY: %.8x\tB2R2_TSZ: %.8x\n" + "\tB2R2_S1XY: %.8x\tB2R2_S1SZ: %.8x\n" + "\tB2R2_S2XY: %.8x\tB2R2_S2SZ: %.8x\n" + "\tB2R2_S3XY: %.8x\tB2R2_S3SZ: %.8x\n" + "-----------------------------------\n", + __func__, node->node.GROUP1.B2R2_TXY, + node->node.GROUP1.B2R2_TSZ, + node->node.GROUP3.B2R2_SXY, + node->node.GROUP3.B2R2_SSZ, + node->node.GROUP4.B2R2_SXY, + node->node.GROUP4.B2R2_SSZ, + node->node.GROUP5.B2R2_SXY, + node->node.GROUP5.B2R2_SSZ); + + node = node->next; + + } while (node != last); + + /* Consume the nodes */ + *next = node; + + return 0; +error: + b2r2_log_warn(cont->dev, "%s: error!\n", __func__); + return ret; +} + +/** + * configure_scale() - configures the given node for scaling + * + * @node - the node to configure + * @src - the source buffer + * @dst - the destination buffer + * @h_rsf - the horizontal rescale factor + * @v_rsf - the vertical rescale factor + * @ivmx - the iVMX to use for color conversion + * @next - the next empty node in the node list + */ +static int configure_scale( + struct b2r2_control *cont, + struct b2r2_node *node, + struct b2r2_node_split_buf *src, + struct b2r2_node_split_buf *dst, + u16 h_rsf, u16 v_rsf, + const u32 *ivmx, struct b2r2_node **next, + struct b2r2_node_split_job *this) +{ + int ret; + + struct b2r2_node *last; + + struct b2r2_filter_spec *hf = NULL; + struct b2r2_filter_spec *vf = NULL; + + u32 fctl = 0; + u32 rsf = 0; + u32 rzi = 0; + u32 hsrc_init = 0; + u32 vsrc_init = 0; + u32 hfp = 0; + u32 vfp = 0; + + u16 luma_h_rsf = h_rsf; + u16 luma_v_rsf = v_rsf; + + struct b2r2_filter_spec *luma_hf = NULL; + struct b2r2_filter_spec *luma_vf = NULL; + + u32 luma_fctl = 0; + u32 luma_rsf = 0; + u32 luma_rzi = 0; + u32 luma_hsrc_init = 0; + u32 luma_vsrc_init = 0; + u32 luma_hfp = 0; + u32 luma_vfp = 0; + + s32 src_x; + s32 src_y; + s32 src_w; + s32 src_h; + + bool upsample; + bool downsample; + + struct b2r2_blt_rect tmp_win = src->win; + bool src_raster = src->type == B2R2_FMT_TYPE_RASTER; + bool dst_raster = dst->type == B2R2_FMT_TYPE_RASTER; + + /* Rescale the normalized source window */ + src_x = inv_rescale(src->win.x - src->rect.x, luma_h_rsf); + src_y = inv_rescale(src->win.y - src->rect.y, luma_v_rsf); + src_w = inv_rescale(src->win.width, luma_h_rsf); + src_h = inv_rescale(src->win.height, luma_v_rsf); + + /* Convert to src coordinate space */ + src->win.x = (src_x >> 10) + src->rect.x; + src->win.y = (src_y >> 10) + src->rect.y; + + /* + * Since the stripe might start and end on a fractional pixel + * we need to count all the touched pixels in the width. + * + * Example: + * src_x = 1.8, src_w = 2.8 + * + * The stripe touches pixels 1.8 through 4.6, i.e. 4 pixels + */ + src->win.width = ((src_x & 0x3ff) + src_w + 0x3ff) >> 10; + src->win.height = ((src_y & 0x3ff) + src_h + 0x3ff) >> 10; + + luma_hsrc_init = src_x & 0x3ff; + luma_vsrc_init = src_y & 0x3ff; + + /* Check for upsampling of chroma */ + upsample = !src_raster && !is_yuv444_fmt(src->fmt); + if (upsample) { + h_rsf /= 2; + + if (is_yuv420_fmt(src->fmt)) + v_rsf /= 2; + } + + /* Check for downsampling of chroma */ + downsample = !dst_raster && !is_yuv444_fmt(dst->fmt); + if (downsample) { + h_rsf *= 2; + + if (is_yuv420_fmt(dst->fmt)) + v_rsf *= 2; + } + + src_x = inv_rescale(tmp_win.x - src->rect.x, h_rsf); + src_y = inv_rescale(tmp_win.y - src->rect.y, v_rsf); + hsrc_init = src_x & 0x3ff; + vsrc_init = src_y & 0x3ff; + + /* Configure resize and filters */ + fctl = B2R2_FCTL_HF2D_MODE_ENABLE_RESIZER | + B2R2_FCTL_VF2D_MODE_ENABLE_RESIZER; + luma_fctl = B2R2_FCTL_LUMA_HF2D_MODE_ENABLE_RESIZER | + B2R2_FCTL_LUMA_VF2D_MODE_ENABLE_RESIZER; + + rsf = (h_rsf << B2R2_RSF_HSRC_INC_SHIFT) | + (v_rsf << B2R2_RSF_VSRC_INC_SHIFT); + luma_rsf = (luma_h_rsf << B2R2_RSF_HSRC_INC_SHIFT) | + (luma_v_rsf << B2R2_RSF_VSRC_INC_SHIFT); + + rzi = B2R2_RZI_DEFAULT_HNB_REPEAT | + (2 << B2R2_RZI_VNB_REPEAT_SHIFT) | + (hsrc_init << B2R2_RZI_HSRC_INIT_SHIFT) | + (vsrc_init << B2R2_RZI_VSRC_INIT_SHIFT); + luma_rzi = B2R2_RZI_DEFAULT_HNB_REPEAT | + (2 << B2R2_RZI_VNB_REPEAT_SHIFT) | + (luma_hsrc_init << B2R2_RZI_HSRC_INIT_SHIFT) | + (luma_vsrc_init << B2R2_RZI_VSRC_INIT_SHIFT); + + /* + * We should only filter if there is an actual rescale (i.e. not when + * up or downsampling). + */ + if (luma_h_rsf != (1 << 10)) { + hf = b2r2_filter_find(h_rsf); + luma_hf = b2r2_filter_find(luma_h_rsf); + } + if (luma_v_rsf != (1 << 10)) { + vf = b2r2_filter_find(v_rsf); + luma_vf = b2r2_filter_find(luma_v_rsf); + } + + if (hf) { + fctl |= B2R2_FCTL_HF2D_MODE_ENABLE_COLOR_CHANNEL_FILTER; + hfp = hf->h_coeffs_phys_addr; + } + + if (vf) { + fctl |= B2R2_FCTL_VF2D_MODE_ENABLE_COLOR_CHANNEL_FILTER; + vfp = vf->v_coeffs_phys_addr; + } + + if (luma_hf) { + luma_fctl |= B2R2_FCTL_LUMA_HF2D_MODE_ENABLE_FILTER; + luma_hfp = luma_hf->h_coeffs_phys_addr; + } + + if (luma_vf) { + luma_fctl |= B2R2_FCTL_LUMA_VF2D_MODE_ENABLE_FILTER; + luma_vfp = luma_vf->v_coeffs_phys_addr; + } + + ret = configure_copy(cont, node, src, dst, ivmx, &last, this); + if (ret < 0) + goto error; + + do { + bool chroma_rescale = + (h_rsf != (1 << 10)) || (v_rsf != (1 << 10)); + bool luma_rescale = + (luma_h_rsf != (1 << 10)) || + (luma_v_rsf != (1 << 10)); + bool dst_chroma = node->node.GROUP1.B2R2_TTY & + B2R2_TTY_CHROMA_NOT_LUMA; + bool dst_luma = !dst_chroma; + + if (node == NULL) { + b2r2_log_warn(cont->dev, "%s: Internal error! Out " + "of nodes!\n", __func__); + ret = -ENOMEM; + goto error; + } + + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_FILTER_CONTROL; + + /* + * If the source format is anything other than raster, we + * always have to enable both chroma and luma resizers. This + * could be a bug in the hardware, since it is not mentioned in + * the specification. + * + * Otherwise, we will only enable the chroma resizer when + * writing chroma and the luma resizer when writing luma + * (or both when writing raster). Also, if there is no rescale + * to be done there's no point in using the resizers. + */ + + if (!src_raster || (chroma_rescale && + (dst_raster || dst_chroma))) { + /* Enable chroma resize */ + node->node.GROUP0.B2R2_INS |= + B2R2_INS_RESCALE2D_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_RESIZE_CHROMA; + node->node.GROUP8.B2R2_FCTL |= fctl; + + node->node.GROUP9.B2R2_RSF = rsf; + node->node.GROUP9.B2R2_RZI = rzi; + node->node.GROUP9.B2R2_HFP = hfp; + node->node.GROUP9.B2R2_VFP = vfp; + } + + if (!src_raster || (luma_rescale && + (dst_raster || dst_luma))) { + /* Enable luma resize */ + node->node.GROUP0.B2R2_INS |= + B2R2_INS_RESCALE2D_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_RESIZE_LUMA; + node->node.GROUP8.B2R2_FCTL |= luma_fctl; + + node->node.GROUP10.B2R2_RSF = luma_rsf; + node->node.GROUP10.B2R2_RZI = luma_rzi; + node->node.GROUP10.B2R2_HFP = luma_hfp; + node->node.GROUP10.B2R2_VFP = luma_vfp; + /* + * Scaling operation from raster to a multi-buffer + * format, requires the raster input to be scaled + * before luminance information can be extracted. + * Raster input is scaled by the chroma resizer. + * Luma resizer only handles luminance data which + * exists in a separate buffer in source image, + * as is the case with YUV planar/semi-planar formats. + */ + if (src_raster) { + /* Activate chroma scaling */ + node->node.GROUP0.B2R2_CIC |= + B2R2_CIC_RESIZE_CHROMA; + node->node.GROUP8.B2R2_FCTL |= fctl; + /* + * Color data must be scaled + * to the same size as luma. + * Use luma scaling parameters. + */ + node->node.GROUP9.B2R2_RSF = luma_rsf; + node->node.GROUP9.B2R2_RZI = luma_rzi; + node->node.GROUP9.B2R2_HFP = luma_hfp; + node->node.GROUP9.B2R2_VFP = luma_vfp; + } + } + + b2r2_log_info(cont->dev, "%s:\n" + "\tB2R2_TXY: %.8x\tB2R2_TSZ: %.8x\n" + "\tB2R2_S1XY: %.8x\tB2R2_S1SZ: %.8x\n" + "\tB2R2_S2XY: %.8x\tB2R2_S2SZ: %.8x\n" + "\tB2R2_S3XY: %.8x\tB2R2_S3SZ: %.8x\n" + "----------------------------------\n", + __func__, node->node.GROUP1.B2R2_TXY, + node->node.GROUP1.B2R2_TSZ, + node->node.GROUP3.B2R2_SXY, + node->node.GROUP3.B2R2_SSZ, + node->node.GROUP4.B2R2_SXY, + node->node.GROUP4.B2R2_SSZ, + node->node.GROUP5.B2R2_SXY, + node->node.GROUP5.B2R2_SSZ); + + node = node->next; + + } while (node != last); + + + + /* Consume the nodes */ + *next = node; + + return 0; +error: + b2r2_log_warn(cont->dev, "%s: Exit...\n", __func__); + return ret; +} + +/** + * configure_src() - configures the source registers and the iVMX + * + * @node - the node to configure + * @src - the source buffer + * @ivmx - the iVMX to use for color conversion + * + * This operation will not consume any nodes + */ +static void configure_src(struct b2r2_control *cont, + struct b2r2_node *node, + struct b2r2_node_split_buf *src, const u32 *ivmx) +{ + struct b2r2_node_split_buf tmp_buf; + + b2r2_log_info(cont->dev, + "%s: src.win=(%d, %d, %d, %d)\n", __func__, + src->win.x, src->win.y, src->win.width, + src->win.height); + + /* Configure S1 - S3 */ + switch (src->type) { + case B2R2_FMT_TYPE_RASTER: + set_src_2(node, src->addr, src); + break; + case B2R2_FMT_TYPE_SEMI_PLANAR: + memcpy(&tmp_buf, src, sizeof(tmp_buf)); + + /* + * For 420 and 422 the chroma has lower resolution than the + * luma + */ + if (!is_yuv444_fmt(src->fmt)) { + tmp_buf.win.x >>= 1; + tmp_buf.win.width = (tmp_buf.win.width + 1) / 2; + + if (is_yuv420_fmt(src->fmt)) { + tmp_buf.win.height = + (tmp_buf.win.height + 1) / 2; + tmp_buf.win.y >>= 1; + } + } + + set_src_3(node, src->addr, src); + set_src_2(node, tmp_buf.chroma_addr, &tmp_buf); + break; + case B2R2_FMT_TYPE_PLANAR: + memcpy(&tmp_buf, src, sizeof(tmp_buf)); + + if (!is_yuv444_fmt(src->fmt)) { + /* + * Each chroma buffer will have half as many values + * per line as the luma buffer + */ + tmp_buf.pitch = (tmp_buf.pitch + 1) / 2; + + /* Horizontal resolution is half */ + tmp_buf.win.x >>= 1; + tmp_buf.win.width = (tmp_buf.win.width + 1) / 2; + + /* + * If the buffer is in YUV420 format, the vertical + * resolution is half as well + */ + if (is_yuv420_fmt(src->fmt)) { + tmp_buf.win.height = + (tmp_buf.win.height + 1) / 2; + tmp_buf.win.y >>= 1; + } + } + + set_src_3(node, src->addr, src); /* Y */ + set_src_2(node, tmp_buf.chroma_addr, &tmp_buf); /* U */ + set_src_1(node, tmp_buf.chroma_cr_addr, &tmp_buf); /* V */ + + break; + default: + /* Should never, ever happen */ + BUG_ON(1); + break; + } + + /* Configure the iVMX for color space conversions */ + if (ivmx != NULL) + set_ivmx(node, ivmx); +} + +/** + * configure_bg() - configures a background for the given node + * + * @node - the node to configure + * @bg - the background buffer + * @swap_fg_bg - if true, fg will be on s1 instead of s2 + * + * This operation will not consume any nodes. + * + * NOTE: This method should be called _AFTER_ the destination has been + * configured. + * + * WARNING: Take care when using this with semi-planar or planar sources since + * either S1 or S2 will be overwritten! + */ +static void configure_bg(struct b2r2_control *cont, + struct b2r2_node *node, + struct b2r2_node_split_buf *bg, bool swap_fg_bg) +{ + b2r2_log_info(cont->dev, + "%s: bg.win=(%d, %d, %d, %d)\n", __func__, + bg->win.x, bg->win.y, bg->win.width, + bg->win.height); + + /* Configure S1 */ + switch (bg->type) { + case B2R2_FMT_TYPE_RASTER: + if (swap_fg_bg) { + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2; + node->node.GROUP0.B2R2_INS |= + B2R2_INS_SOURCE_2_FETCH_FROM_MEM; + node->node.GROUP0.B2R2_ACK |= B2R2_ACK_SWAP_FG_BG; + + set_src(&node->node.GROUP4, bg->addr, bg); + } else { + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_1; + node->node.GROUP0.B2R2_INS |= + B2R2_INS_SOURCE_1_FETCH_FROM_MEM; + + set_src(&node->node.GROUP3, bg->addr, bg); + } + break; + default: + /* Should never, ever happen */ + BUG_ON(1); + break; + } +} + +/** + * configure_dst() - configures the destination registers of the given node + * + * @node - the node to configure + * @ivmx - the iVMX to use for color conversion + * @dst - the destination buffer + * + * This operation will consume as many nodes as are required to write the + * destination format. + */ +static int configure_dst(struct b2r2_control *cont, struct b2r2_node *node, + struct b2r2_node_split_buf *dst, const u32 *ivmx, + struct b2r2_node **next) +{ + int ret; + int nbr_planes = 1; + int i; + + struct b2r2_node_split_buf dst_planes[3]; + + b2r2_log_info(cont->dev, + "%s: dst.win=(%d, %d, %d, %d)\n", __func__, + dst->win.x, dst->win.y, dst->win.width, + dst->win.height); + + memcpy(&dst_planes[0], dst, sizeof(dst_planes[0])); + + if (dst->type != B2R2_FMT_TYPE_RASTER) { + /* There will be at least 2 planes */ + nbr_planes = 2; + + memcpy(&dst_planes[1], dst, sizeof(dst_planes[1])); + + dst_planes[1].addr = dst->chroma_addr; + dst_planes[1].plane_selection = B2R2_TTY_CHROMA_NOT_LUMA; + + if (!is_yuv444_fmt(dst->fmt)) { + /* Horizontal resolution is half */ + dst_planes[1].win.x /= 2; + /* + * Must round up the chroma size to handle cases when + * luma size is not divisible by 2. E.g. luma width==7 r + * equires chroma width==4. Chroma width==7/2==3 is only + * enough for luma width==6. + */ + dst_planes[1].win.width = + (dst_planes[1].win.width + 1) / 2; + + /* + * If the buffer is in YUV420 format, the vertical + * resolution is half as well. Height must be rounded in + * the same way as is done for width. + */ + if (is_yuv420_fmt(dst->fmt)) { + dst_planes[1].win.y /= 2; + dst_planes[1].win.height = + (dst_planes[1].win.height + 1) / 2; + } + } + + if (dst->type == B2R2_FMT_TYPE_PLANAR) { + /* There will be a third plane as well */ + nbr_planes = 3; + + if (!is_yuv444_fmt(dst->fmt)) { + /* The chroma planes have half the luma pitch */ + dst_planes[1].pitch /= 2; + } + + memcpy(&dst_planes[2], &dst_planes[1], + sizeof(dst_planes[2])); + dst_planes[2].addr = dst->chroma_cr_addr; + + /* + * The third plane will be Cr. + * The flag B2R2_TTY_CB_NOT_CR actually works + * the other way around, i.e. as if it was + * B2R2_TTY_CR_NOT_CB. + */ + dst_planes[2].chroma_selection = B2R2_TTY_CB_NOT_CR; + } + + } + + /* Configure one node for each plane */ + for (i = 0; i < nbr_planes; i++) { + + if (node == NULL) { + b2r2_log_warn(cont->dev, "%s: " + "Internal error! Out of nodes!\n", __func__); + ret = -ENOMEM; + goto error; + } + + /* + * When writing chroma, there's no need to read the luma and + * vice versa. + */ + if ((node->node.GROUP3.B2R2_STY & B2R2_NATIVE_YUV) && + (nbr_planes > 1)) { + if (i != 0) { + node->node.GROUP4.B2R2_STY |= + B2R2_S3TY_ENABLE_BLANK_ACCESS; + } + if (i != 1) { + node->node.GROUP0.B2R2_INS &= + ~B2R2_INS_SOURCE_2_FETCH_FROM_MEM; + node->node.GROUP0.B2R2_INS |= + B2R2_INS_SOURCE_2_COLOR_FILL_REGISTER; + } + if (i != 2) { + node->node.GROUP0.B2R2_INS &= + ~B2R2_INS_SOURCE_1_FETCH_FROM_MEM; + node->node.GROUP0.B2R2_INS |= + B2R2_INS_SOURCE_1_COLOR_FILL_REGISTER; + } + } else if ((node->node.GROUP3.B2R2_STY & + (B2R2_NATIVE_YCBCR42X_MBN | + B2R2_NATIVE_YCBCR42X_R2B)) && + (nbr_planes > 1)) { + if (i != 0) { + node->node.GROUP4.B2R2_STY |= + B2R2_S3TY_ENABLE_BLANK_ACCESS; + } + } + + set_target(node, dst_planes[i].addr, &dst_planes[i]); + + node = node->next; + } + + /* Consume the nodes */ + *next = node; + + return 0; +error: + b2r2_log_warn(cont->dev, "%s: Exit...\n", __func__); + return ret; + +} + +/** + * configure_blend() - configures the given node for alpha blending + * + * @node - the node to configure + * @flags - the flags passed in the blt_request + * @global_alpha - the global alpha to use (if enabled in flags) + * + * This operation will not consume any nodes. + * + * NOTE: This method should be called _AFTER_ the destination has been + * configured. + * + * WARNING: Take care when using this with semi-planar or planar sources since + * either S1 or S2 will be overwritten! + */ +static void configure_blend(struct b2r2_control *cont, + struct b2r2_node *node, u32 flags, u32 global_alpha) +{ + node->node.GROUP0.B2R2_ACK &= ~(B2R2_ACK_MODE_BYPASS_S2_S3); + + /* Check if the foreground is premultiplied */ + if ((flags & B2R2_BLT_FLAG_SRC_IS_NOT_PREMULT) != 0) + node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BLEND_NOT_PREMULT; + else + node->node.GROUP0.B2R2_ACK |= B2R2_ACK_MODE_BLEND_PREMULT; + + /* Check if global alpha blend should be enabled */ + if (flags & B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND) { + + /* B2R2 expects the global alpha to be in 0...128 range */ + global_alpha = (global_alpha*128)/255; + + node->node.GROUP0.B2R2_ACK |= + global_alpha << B2R2_ACK_GALPHA_ROPID_SHIFT; + } else { + node->node.GROUP0.B2R2_ACK |= + (128 << B2R2_ACK_GALPHA_ROPID_SHIFT); + } +} + +/** + * configure_clip() - configures destination clipping for the given node + * + * @node - the node to configure + * @clip_rect - the clip rectangle + * + * This operation does not consume any nodes. + */ +static void configure_clip(struct b2r2_control *cont, struct b2r2_node *node, + struct b2r2_blt_rect *clip_rect) +{ + s32 l = clip_rect->x; + s32 r = clip_rect->x + clip_rect->width - 1; + s32 t = clip_rect->y; + s32 b = clip_rect->y + clip_rect->height - 1; + + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_CLIP_WINDOW; + node->node.GROUP0.B2R2_INS |= B2R2_INS_RECT_CLIP_ENABLED; + + /* Clip window setup */ + node->node.GROUP6.B2R2_CWO = + ((t & 0x7FFF) << B2R2_CWO_Y_SHIFT) | + ((l & 0x7FFF) << B2R2_CWO_X_SHIFT); + node->node.GROUP6.B2R2_CWS = + ((b & 0x7FFF) << B2R2_CWO_Y_SHIFT) | + ((r & 0x7FFF) << B2R2_CWO_X_SHIFT); +} + +/** + * set_buf() - configures the given buffer with the provided values + * + * @addr - the physical base address + * @img - the blt image to base the buffer on + * @rect - the rectangle to use + * @color_fill - determines whether the buffer should be used for color fill + * @color - the color to use in case of color fill + */ +static void set_buf(struct b2r2_control *cont, + struct b2r2_node_split_buf *buf, + u32 addr, + const struct b2r2_blt_img *img, + const struct b2r2_blt_rect *rect, + bool color_fill, + u32 color) +{ + memset(buf, 0, sizeof(*buf)); + + buf->fmt = img->fmt; + buf->type = get_fmt_type(img->fmt); + + if (color_fill) { + buf->type = B2R2_FMT_TYPE_RASTER; + buf->color = color; + } else { + buf->addr = addr; + + buf->alpha_range = get_alpha_range(img->fmt); + + if (img->pitch == 0) + buf->pitch = fmt_byte_pitch(img->fmt, img->width); + else + buf->pitch = img->pitch; + + buf->height = img->height; + buf->width = img->width; + + switch (buf->type) { + case B2R2_FMT_TYPE_SEMI_PLANAR: + buf->chroma_addr = (u32)(((u8 *)addr) + + buf->pitch * buf->height); + break; + case B2R2_FMT_TYPE_PLANAR: + if (is_yuv422_fmt(buf->fmt) || + is_yuv420_fmt(buf->fmt)) { + buf->chroma_addr = (u32)(((u8 *)addr) + + buf->pitch * buf->height); + } else { + buf->chroma_cr_addr = (u32)(((u8 *)addr) + + buf->pitch * buf->height); + } + if (is_yuv420_fmt(buf->fmt)) { + /* + * Use ceil(height/2) in case + * buffer height is not divisible by 2. + */ + buf->chroma_cr_addr = + (u32)(((u8 *)buf->chroma_addr) + + (buf->pitch >> 1) * + ((buf->height + 1) >> 1)); + } else if (is_yuv422_fmt(buf->fmt)) { + buf->chroma_cr_addr = + (u32)(((u8 *)buf->chroma_addr) + + (buf->pitch >> 1) * buf->height); + } else if (is_yvu420_fmt(buf->fmt)) { + buf->chroma_addr = + (u32)(((u8 *)buf->chroma_cr_addr) + + (buf->pitch >> 1) * + ((buf->height + 1) >> 1)); + } else if (is_yvu422_fmt(buf->fmt)) { + buf->chroma_addr = + (u32)(((u8 *)buf->chroma_cr_addr) + + (buf->pitch >> 1) * buf->height); + } + break; + default: + break; + } + + memcpy(&buf->rect, rect, sizeof(buf->rect)); + } +} + +/** + * setup_tmp_buf() - configure a temporary buffer + */ +static int setup_tmp_buf(struct b2r2_control *cont, + struct b2r2_node_split_buf *tmp, + u32 max_size, + enum b2r2_blt_fmt pref_fmt, + u32 pref_width, + u32 pref_height) +{ + int ret; + + enum b2r2_blt_fmt fmt; + + u32 width; + u32 height; + u32 pitch; + u32 size; + + /* Determine what format we should use for the tmp buf */ + if (is_rgb_fmt(pref_fmt)) { + fmt = B2R2_BLT_FMT_32_BIT_ARGB8888; + } else if (is_bgr_fmt(pref_fmt)) { + fmt = B2R2_BLT_FMT_32_BIT_ABGR8888; + } else if (is_yvu_fmt(pref_fmt)) { + fmt = B2R2_BLT_FMT_CB_Y_CR_Y; + } else if (is_yuv_fmt(pref_fmt)) { + fmt = B2R2_BLT_FMT_32_BIT_AYUV8888; + } else { + /* Wait, what? */ + b2r2_log_warn(cont->dev, "%s: " + "Cannot create tmp buf from this fmt (%d)\n", + __func__, pref_fmt); + ret = -EINVAL; + goto error; + } + + /* See if we can fit the entire preferred rectangle */ + width = pref_width; + height = pref_height; + pitch = fmt_byte_pitch(fmt, width); + size = pitch * height; + + if (size > max_size) { + /* We need to limit the size, so we choose a different width */ + width = MIN(width, B2R2_RESCALE_MAX_WIDTH); + pitch = fmt_byte_pitch(fmt, width); + height = MIN(height, max_size / pitch); + size = pitch * height; + } + + /* We should at least have enough room for one scanline */ + if (height == 0) { + b2r2_log_warn(cont->dev, "%s: Not enough tmp mem!\n", + __func__); + ret = -ENOMEM; + goto error; + } + + memset(tmp, 0, sizeof(*tmp)); + + tmp->fmt = fmt; + tmp->type = B2R2_FMT_TYPE_RASTER; + tmp->height = height; + tmp->width = width; + tmp->pitch = pitch; + + tmp->rect.width = width; + tmp->rect.height = tmp->height; + tmp->alpha_range = B2R2_TY_ALPHA_RANGE_255; + + return 0; +error: + b2r2_log_warn(cont->dev, "%s: Exit...\n", __func__); + return ret; + +} + +/** + * get_alpha_range() - returns the alpha range of the given format + */ +static enum b2r2_ty get_alpha_range(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_24_BIT_ARGB8565: + case B2R2_BLT_FMT_32_BIT_ARGB8888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + case B2R2_BLT_FMT_8_BIT_A8: + case B2R2_BLT_FMT_32_BIT_ABGR8888: + return B2R2_TY_ALPHA_RANGE_255; /* 0 - 255 */ + default: + return B2R2_TY_ALPHA_RANGE_128; /* 0 - 128 */ + } +} + +/** + * get_alpha() - returns the pixel alpha in 0...255 range + */ +static u8 get_alpha(enum b2r2_blt_fmt fmt, u32 pixel) +{ + switch (fmt) { + case B2R2_BLT_FMT_32_BIT_ARGB8888: + case B2R2_BLT_FMT_32_BIT_ABGR8888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + return (pixel >> 24) & 0xff; + case B2R2_BLT_FMT_32_BIT_VUYA8888: + return pixel & 0xff; + case B2R2_BLT_FMT_24_BIT_ARGB8565: + return (pixel & 0xfff) >> 16; + case B2R2_BLT_FMT_16_BIT_ARGB4444: + return (((pixel >> 12) & 0xf) * 255) / 15; + case B2R2_BLT_FMT_16_BIT_ARGB1555: + return (pixel >> 15) * 255; + case B2R2_BLT_FMT_1_BIT_A1: + return pixel * 255; + case B2R2_BLT_FMT_8_BIT_A8: + return pixel; + default: + return 255; + } +} + +/** + * set_alpha() - returns a color value with the alpha component set + */ +static u32 set_alpha(enum b2r2_blt_fmt fmt, u8 alpha, u32 color) +{ + u32 alpha_mask; + + switch (fmt) { + case B2R2_BLT_FMT_32_BIT_ARGB8888: + case B2R2_BLT_FMT_32_BIT_ABGR8888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + color &= 0x00ffffff; + alpha_mask = alpha << 24; + break; + case B2R2_BLT_FMT_32_BIT_VUYA8888: + color &= 0xffffff00; + alpha_mask = alpha; + break; + case B2R2_BLT_FMT_24_BIT_ARGB8565: + color &= 0x00ffff; + alpha_mask = alpha << 16; + break; + case B2R2_BLT_FMT_16_BIT_ARGB4444: + color &= 0x0fff; + alpha_mask = (alpha << 8) & 0xF000; + break; + case B2R2_BLT_FMT_16_BIT_ARGB1555: + color &= 0x7fff; + alpha_mask = (alpha / 255) << 15 ; + break; + case B2R2_BLT_FMT_1_BIT_A1: + color = 0; + alpha_mask = (alpha / 255); + break; + case B2R2_BLT_FMT_8_BIT_A8: + color = 0; + alpha_mask = alpha; + break; + default: + alpha_mask = 0; + } + + return color | alpha_mask; +} + +/** + * fmt_has_alpha() - returns whether the given format carries an alpha value + */ +static bool fmt_has_alpha(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_16_BIT_ARGB4444: + case B2R2_BLT_FMT_16_BIT_ARGB1555: + case B2R2_BLT_FMT_32_BIT_ARGB8888: + case B2R2_BLT_FMT_32_BIT_ABGR8888: + case B2R2_BLT_FMT_24_BIT_ARGB8565: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + case B2R2_BLT_FMT_1_BIT_A1: + case B2R2_BLT_FMT_8_BIT_A8: + return true; + default: + return false; + } +} + +/** + * is_rgb_fmt() - returns whether the given format is a rgb format + */ +static bool is_rgb_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_16_BIT_ARGB4444: + case B2R2_BLT_FMT_16_BIT_ARGB1555: + case B2R2_BLT_FMT_16_BIT_RGB565: + case B2R2_BLT_FMT_24_BIT_RGB888: + case B2R2_BLT_FMT_32_BIT_ARGB8888: + case B2R2_BLT_FMT_24_BIT_ARGB8565: + case B2R2_BLT_FMT_1_BIT_A1: + case B2R2_BLT_FMT_8_BIT_A8: + return true; + default: + return false; + } +} + +/** + * is_bgr_fmt() - returns whether the given format is a bgr format + */ +static bool is_bgr_fmt(enum b2r2_blt_fmt fmt) +{ + return (fmt == B2R2_BLT_FMT_32_BIT_ABGR8888); +} + +/** + * is_yuv_fmt() - returns whether the given format is a yuv format + */ +static bool is_yuv_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + return true; + default: + return false; + } +} + +/** + * is_yvu_fmt() - returns whether the given format is a yvu format + */ +static bool is_yvu_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + return true; + default: + return false; + } +} + +/** + * is_yuv420_fmt() - returns whether the given format is a yuv420 format + */ +static bool is_yuv420_fmt(enum b2r2_blt_fmt fmt) +{ + + switch (fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + return true; + default: + return false; + } +} + +static bool is_yuv422_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + return true; + default: + return false; + } +} + +/** + * is_yvu420_fmt() - returns whether the given format is a yvu420 format + */ +static bool is_yvu420_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + return true; + default: + return false; + } +} + +static bool is_yvu422_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_CB_Y_CR_Y: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + return true; + default: + return false; + } +} + + +/** + * is_yuv444_fmt() - returns whether the given format is a yuv444 format + */ +static bool is_yuv444_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + return true; + default: + return false; + } +} + +/** + * get_fmt_byte_pitch() - returns the pitch of a pixmap with the given width + */ +static int fmt_byte_pitch(enum b2r2_blt_fmt fmt, u32 width) +{ + int pitch; + + switch (fmt) { + + case B2R2_BLT_FMT_1_BIT_A1: + pitch = width >> 3; /* Shift is faster than division */ + if ((width & 0x3) != 0) /* Check for remainder */ + pitch++; + return pitch; + + case B2R2_BLT_FMT_8_BIT_A8: /* Fall through */ + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: /* Fall through */ + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: /* Fall through */ + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: /* Fall through */ + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: /* Fall through */ + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: /* Fall through */ + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: /* Fall through */ + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: /* Fall through */ + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: /* Fall through */ + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: /* Fall through */ + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: /* Fall through */ + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + return width; + + case B2R2_BLT_FMT_16_BIT_ARGB4444: /* Fall through */ + case B2R2_BLT_FMT_16_BIT_ARGB1555: /* Fall through */ + case B2R2_BLT_FMT_16_BIT_RGB565: /* Fall through */ + case B2R2_BLT_FMT_Y_CB_Y_CR: /* Fall through */ + case B2R2_BLT_FMT_CB_Y_CR_Y: + return width << 1; + + case B2R2_BLT_FMT_24_BIT_RGB888: /* Fall through */ + case B2R2_BLT_FMT_24_BIT_ARGB8565: /* Fall through */ + case B2R2_BLT_FMT_24_BIT_YUV888: /* Fall through */ + case B2R2_BLT_FMT_24_BIT_VUY888: + return width * 3; + + case B2R2_BLT_FMT_32_BIT_ARGB8888: /* Fall through */ + case B2R2_BLT_FMT_32_BIT_ABGR8888: /* Fall through */ + case B2R2_BLT_FMT_32_BIT_AYUV8888: /* Fall through */ + case B2R2_BLT_FMT_32_BIT_VUYA8888: + return width << 2; + + default: + /* Should never, ever happen */ + BUG_ON(1); + return 0; + } +} + +/** + * to_native_fmt() - returns the native B2R2 format + */ +static enum b2r2_native_fmt to_native_fmt(enum b2r2_blt_fmt fmt) +{ + + switch (fmt) { + case B2R2_BLT_FMT_UNUSED: + return B2R2_NATIVE_RGB565; + case B2R2_BLT_FMT_1_BIT_A1: + return B2R2_NATIVE_A1; + case B2R2_BLT_FMT_8_BIT_A8: + return B2R2_NATIVE_A8; + case B2R2_BLT_FMT_16_BIT_RGB565: + return B2R2_NATIVE_RGB565; + case B2R2_BLT_FMT_16_BIT_ARGB4444: + return B2R2_NATIVE_ARGB4444; + case B2R2_BLT_FMT_16_BIT_ARGB1555: + return B2R2_NATIVE_ARGB1555; + case B2R2_BLT_FMT_24_BIT_ARGB8565: + return B2R2_NATIVE_ARGB8565; + case B2R2_BLT_FMT_24_BIT_RGB888: + return B2R2_NATIVE_RGB888; + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_24_BIT_VUY888: /* Not actually supported by HW */ + return B2R2_NATIVE_YCBCR888; + case B2R2_BLT_FMT_32_BIT_ABGR8888: /* Not actually supported by HW */ + case B2R2_BLT_FMT_32_BIT_ARGB8888: + return B2R2_NATIVE_ARGB8888; + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: /* Not actually supported by HW */ + return B2R2_NATIVE_AYCBCR8888; + case B2R2_BLT_FMT_CB_Y_CR_Y: + return B2R2_NATIVE_YCBCR422R; + case B2R2_BLT_FMT_Y_CB_Y_CR: + return B2R2_NATIVE_YCBCR422R; + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + return B2R2_NATIVE_YCBCR42X_R2B; + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + return B2R2_NATIVE_YCBCR42X_MBN; + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + return B2R2_NATIVE_YUV; + default: + /* Should never ever happen */ + return B2R2_NATIVE_BYTE; + } +} + +/** + * Bit-expand the color from fmt to RGB888 with blue at LSB. + * Copy MSBs into missing LSBs. + */ +static u32 to_RGB888(u32 color, const enum b2r2_blt_fmt fmt) +{ + u32 out_color = 0; + u32 r = 0; + u32 g = 0; + u32 b = 0; + switch (fmt) { + case B2R2_BLT_FMT_16_BIT_ARGB4444: + r = ((color & 0xf00) << 12) | ((color & 0xf00) << 8); + g = ((color & 0xf0) << 8) | ((color & 0xf0) << 4); + b = ((color & 0xf) << 4) | (color & 0xf); + out_color = r | g | b; + break; + case B2R2_BLT_FMT_16_BIT_ARGB1555: + r = ((color & 0x7c00) << 9) | ((color & 0x7000) << 4); + g = ((color & 0x3e0) << 6) | ((color & 0x380) << 1); + b = ((color & 0x1f) << 3) | ((color & 0x1c) >> 2); + out_color = r | g | b; + break; + case B2R2_BLT_FMT_16_BIT_RGB565: + r = ((color & 0xf800) << 8) | ((color & 0xe000) << 3); + g = ((color & 0x7e0) << 5) | ((color & 0x600) >> 1); + b = ((color & 0x1f) << 3) | ((color & 0x1c) >> 2); + out_color = r | g | b; + break; + case B2R2_BLT_FMT_24_BIT_RGB888: + case B2R2_BLT_FMT_32_BIT_ARGB8888: + out_color = color & 0xffffff; + break; + case B2R2_BLT_FMT_32_BIT_ABGR8888: + r = (color & 0xff) << 16; + g = color & 0xff00; + b = (color & 0xff0000) >> 16; + out_color = r | g | b; + break; + case B2R2_BLT_FMT_24_BIT_ARGB8565: + r = ((color & 0xf800) << 8) | ((color & 0xe000) << 3); + g = ((color & 0x7e0) << 5) | ((color & 0x600) >> 1); + b = ((color & 0x1f) << 3) | ((color & 0x1c) >> 2); + out_color = r | g | b; + break; + default: + break; + } + + return out_color; +} + +/** + * get_fmt_type() - returns the type of the given format (raster, planar, etc.) + */ +static enum b2r2_fmt_type get_fmt_type(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_16_BIT_ARGB4444: + case B2R2_BLT_FMT_16_BIT_ARGB1555: + case B2R2_BLT_FMT_16_BIT_RGB565: + case B2R2_BLT_FMT_24_BIT_RGB888: + case B2R2_BLT_FMT_32_BIT_ARGB8888: + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + case B2R2_BLT_FMT_32_BIT_ABGR8888: + case B2R2_BLT_FMT_24_BIT_ARGB8565: + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + case B2R2_BLT_FMT_1_BIT_A1: + case B2R2_BLT_FMT_8_BIT_A8: + return B2R2_FMT_TYPE_RASTER; + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + return B2R2_FMT_TYPE_PLANAR; + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + return B2R2_FMT_TYPE_SEMI_PLANAR; + default: + return B2R2_FMT_TYPE_RASTER; + } +} + +/** + * is_transform() - returns whether the given request is a transform operation + */ +static bool is_transform(const struct b2r2_blt_request *req) +{ + return (req->user_req.transform != B2R2_BLT_TRANSFORM_NONE) || + (req->user_req.src_rect.width != + req->user_req.dst_rect.width) || + (req->user_req.src_rect.height != + req->user_req.dst_rect.height); +} + +/** + * rescale() - rescales the given dimension + * + * Returns the rescaled dimension in 22.10 fixed point format. + */ +static s32 rescale(struct b2r2_control *cont, s32 dim, u16 sf) +{ + b2r2_log_info(cont->dev, "%s\n", __func__); + + if (sf == 0) { + b2r2_log_err(cont->dev, "%s: Scale factor is 0!\n", __func__); + BUG_ON(1); + } + + /* + * This is normally not safe to do, since it drastically decreases the + * precision of the integer part of the dimension. But since the B2R2 + * hardware only has 12-bit registers for these values, we are safe. + */ + return (dim << 20) / sf; +} + +/** + * inv_rescale() - does an inverted rescale of the given dimension + * + * Returns the rescaled dimension in 22.10 fixed point format. + */ +static s32 inv_rescale(s32 dim, u16 sf) +{ + if (sf == 0) + return dim; + + return dim * sf; +} + +/** + * set_target() - sets the target registers of the given node + */ +static void set_target(struct b2r2_node *node, u32 addr, + struct b2r2_node_split_buf *buf) +{ + s32 l; + s32 r; + s32 t; + s32 b; + + if (buf->tmp_buf_index) + node->dst_tmp_index = buf->tmp_buf_index; + + node->node.GROUP1.B2R2_TBA = addr; + node->node.GROUP1.B2R2_TTY = buf->pitch | to_native_fmt(buf->fmt) | + buf->alpha_range | buf->chroma_selection | buf->hso | + buf->vso | buf->dither | buf->plane_selection; + + if (buf->fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + buf->fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) + node->node.GROUP1.B2R2_TTY |= B2R2_TY_ENDIAN_BIG_NOT_LITTLE; + + node->node.GROUP1.B2R2_TSZ = + ((buf->win.width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) | + ((buf->win.height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + node->node.GROUP1.B2R2_TXY = + ((buf->win.x & 0xffff) << B2R2_XY_X_SHIFT) | + ((buf->win.y & 0xffff) << B2R2_XY_Y_SHIFT); + + /* Check if the rectangle is outside the buffer */ + if (buf->vso == B2R2_TY_VSO_BOTTOM_TO_TOP) + t = buf->win.y - (buf->win.height - 1); + else + t = buf->win.y; + + if (buf->hso == B2R2_TY_HSO_RIGHT_TO_LEFT) + l = buf->win.x - (buf->win.width - 1); + else + l = buf->win.x; + + r = l + buf->win.width; + b = t + buf->win.height; + + /* Clip to the destination buffer to prevent memory overwrites */ + if ((l < 0) || (r > buf->width) || (t < 0) || (b > buf->height)) { + /* The clip rectangle is including the borders */ + l = MAX(l, 0); + r = MIN(r, buf->width) - 1; + t = MAX(t, 0); + b = MIN(b, buf->height) - 1; + + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_CLIP_WINDOW; + node->node.GROUP0.B2R2_INS |= B2R2_INS_RECT_CLIP_ENABLED; + node->node.GROUP6.B2R2_CWO = + ((l & 0x7FFF) << B2R2_CWS_X_SHIFT) | + ((t & 0x7FFF) << B2R2_CWS_Y_SHIFT); + node->node.GROUP6.B2R2_CWS = + ((r & 0x7FFF) << B2R2_CWO_X_SHIFT) | + ((b & 0x7FFF) << B2R2_CWO_Y_SHIFT); + } + +} + +/** + * set_src() - configures the given source register with the given values + */ +static void set_src(struct b2r2_src_config *src, u32 addr, + struct b2r2_node_split_buf *buf) +{ + src->B2R2_SBA = addr; + src->B2R2_STY = buf->pitch | to_native_fmt(buf->fmt) | + buf->alpha_range | buf->hso | buf->vso; + + if (buf->fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + buf->fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) + src->B2R2_STY |= B2R2_TY_ENDIAN_BIG_NOT_LITTLE; + + src->B2R2_SSZ = ((buf->win.width & 0xfff) << B2R2_SZ_WIDTH_SHIFT) | + ((buf->win.height & 0xfff) << B2R2_SZ_HEIGHT_SHIFT); + src->B2R2_SXY = ((buf->win.x & 0xffff) << B2R2_XY_X_SHIFT) | + ((buf->win.y & 0xffff) << B2R2_XY_Y_SHIFT); + +} + +/** + * set_src_1() - sets the source 1 registers of the given node + */ +static void set_src_1(struct b2r2_node *node, u32 addr, + struct b2r2_node_split_buf *buf) +{ + if (buf->tmp_buf_index) + node->src_tmp_index = buf->tmp_buf_index; + + node->src_index = 1; + + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_1; + node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_1_FETCH_FROM_MEM; + + node->node.GROUP3.B2R2_SBA = addr; + node->node.GROUP3.B2R2_STY = buf->pitch | to_native_fmt(buf->fmt) | + buf->alpha_range | buf->hso | buf->vso; + + if (buf->fmt == B2R2_BLT_FMT_24_BIT_VUY888 || + buf->fmt == B2R2_BLT_FMT_32_BIT_VUYA8888) + node->node.GROUP3.B2R2_STY |= B2R2_TY_ENDIAN_BIG_NOT_LITTLE; + + node->node.GROUP3.B2R2_SXY = + ((buf->win.x & 0xffff) << B2R2_XY_X_SHIFT) | + ((buf->win.y & 0xffff) << B2R2_XY_Y_SHIFT); + + /* Source 1 has no size register */ +} + +/** + * set_src_2() - sets the source 2 registers of the given node + */ +static void set_src_2(struct b2r2_node *node, u32 addr, + struct b2r2_node_split_buf *buf) +{ + if (buf->tmp_buf_index) + node->src_tmp_index = buf->tmp_buf_index; + + node->src_index = 2; + + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_2; + node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_2_FETCH_FROM_MEM; + + set_src(&node->node.GROUP4, addr, buf); +} + +/** + * set_src_3() - sets the source 3 registers of the given node + */ +static void set_src_3(struct b2r2_node *node, u32 addr, + struct b2r2_node_split_buf *buf) +{ + if (buf->tmp_buf_index) + node->src_tmp_index = buf->tmp_buf_index; + + node->src_index = 3; + + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_SOURCE_3; + node->node.GROUP0.B2R2_INS |= B2R2_INS_SOURCE_3_FETCH_FROM_MEM; + + set_src(&node->node.GROUP5, addr, buf); +} + +/** + * set_ivmx() - configures the iVMX registers with the given values + */ +static void set_ivmx(struct b2r2_node *node, const u32 *vmx_values) +{ + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + + node->node.GROUP15.B2R2_VMX0 = vmx_values[0]; + node->node.GROUP15.B2R2_VMX1 = vmx_values[1]; + node->node.GROUP15.B2R2_VMX2 = vmx_values[2]; + node->node.GROUP15.B2R2_VMX3 = vmx_values[3]; +} + +/** + * reset_nodes() - clears the node list + */ +static void reset_nodes(struct b2r2_node *node) +{ + while (node != NULL) { + memset(&node->node, 0, sizeof(node->node)); + + node->src_tmp_index = 0; + node->dst_tmp_index = 0; + + /* TODO: Implement support for short linked lists */ + node->node.GROUP0.B2R2_CIC = 0x7ffff; + + if (node->next != NULL) + node->node.GROUP0.B2R2_NIP = + node->next->physical_address; + node = node->next; + } +} + +int b2r2_node_split_init(struct b2r2_control *cont) +{ + return 0; +} + +void b2r2_node_split_exit(struct b2r2_control *cont) +{ + +} diff --git a/drivers/video/b2r2/b2r2_node_split.h b/drivers/video/b2r2/b2r2_node_split.h new file mode 100644 index 00000000000..a577241c31b --- /dev/null +++ b/drivers/video/b2r2/b2r2_node_split.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 node splitter + * + * Author: Fredrik Allansson <fredrik.allansson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __B2R2_NODE_SPLIT_H_ +#define __B2R2_NODE_SPLIT_H_ + +#include "b2r2_internal.h" +#include "b2r2_hw.h" + +/** + * b2r2_node_split_analyze() - Analyzes a B2R2 request + * + * @req - The request to analyze + * @max_buf_size - The largest size allowed for intermediate buffers + * @node_count - Number of nodes required for the job + * @buf_count - Number of intermediate buffers required for the job + * @bufs - An array of buffers needed for intermediate buffers + * + * Analyzes the request and determines how many nodes and intermediate buffers + * are required. + * + * It is the responsibility of the caller to allocate memory and assign the + * physical addresses. After that b2r2_node_split_assign_buffers should be + * called to assign the buffers to the right nodes. + * + * Returns: + * A handle identifing the analyzed request if successful, a negative + * value otherwise. + */ +int b2r2_node_split_analyze(const struct b2r2_blt_request *req, u32 max_buf_size, + u32 *node_count, struct b2r2_work_buf **bufs, u32* buf_count, + struct b2r2_node_split_job *job); + +/** + * b2r2_node_split_configure() - Performs a node split + * + * @handle - A handle for the analyzed request + * @first - The first node in the list of nodes to use + * + * Fills the supplied list of nodes with the parameters acquired by analyzing + * the request. + * + * All pointers to intermediate buffers are represented by integers to be used + * in the array returned by b2r2_node_split_analyze. + * + * Returns: + * A negative value if an error occurred, 0 otherwise. + */ +int b2r2_node_split_configure(struct b2r2_control *cont, + struct b2r2_node_split_job *job, struct b2r2_node *first); + +/** + * b2r2_node_split_assign_buffers() - Assignes physical addresses + * + * @handle - The handle for the job + * @first - The first node in the node list + * @bufs - Buffers with assigned physical addresses + * @buf_count - Number of physical addresses + * + * Assigns the physical addresses where intermediate buffers are required in + * the node list. + * + * The order of the elements of 'bufs' must be maintained from the call to + * b2r2_node_split_analyze. + * + * Returns: + * A negative value if an error occurred, 0 otherwise. + */ +int b2r2_node_split_assign_buffers(struct b2r2_control *cont, + struct b2r2_node_split_job *job, + struct b2r2_node *first, struct b2r2_work_buf *bufs, + u32 buf_count); + +/** + * b2r2_node_split_unassign_buffers() - Removes all physical addresses + * + * @handle - The handle associated with the job + * @first - The first node in the node list + * + * Removes all references to intermediate buffers from the node list. + * + * This makes it possible to reuse the node list with new buffers by calling + * b2r2_node_split_assign_buffers again. Useful for caching node lists. + */ +void b2r2_node_split_unassign_buffers(struct b2r2_control *cont, + struct b2r2_node_split_job *job, + struct b2r2_node *first); + +/** + * b2r2_node_split_release() - Releases all resources for a job + * + * @handle - The handle identifying the job. This will be set to 0. + * + * Releases all resources associated with a job. + * + * This should always be called once b2r2_node_split_analyze has been called + * in order to release any resources allocated while analyzing. + */ +void b2r2_node_split_cancel(struct b2r2_control *cont, + struct b2r2_node_split_job *job); + +/** + * b2r2_node_split_init() - Initializes the node split module + * + * Initializes the node split module and creates debugfs files. + */ +int b2r2_node_split_init(struct b2r2_control *cont); + +/** + * b2r2_node_split_exit() - Deinitializes the node split module + * + * Releases all resources for the node split module. + */ +void b2r2_node_split_exit(struct b2r2_control *cont); + +#endif diff --git a/drivers/video/b2r2/b2r2_profiler/Makefile b/drivers/video/b2r2/b2r2_profiler/Makefile new file mode 100644 index 00000000000..69a85524fd7 --- /dev/null +++ b/drivers/video/b2r2/b2r2_profiler/Makefile @@ -0,0 +1,3 @@ +# Make file for loadable module B2R2 Profiler + +obj-$(CONFIG_B2R2_PROFILER) += b2r2_profiler.o diff --git a/drivers/video/b2r2/b2r2_profiler/b2r2_profiler.c b/drivers/video/b2r2/b2r2_profiler/b2r2_profiler.c new file mode 100644 index 00000000000..e038941b4e8 --- /dev/null +++ b/drivers/video/b2r2/b2r2_profiler/b2r2_profiler.c @@ -0,0 +1,270 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * + * ST-Ericsson B2R2 profiler implementation + * + * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/jiffies.h> + +#include <video/b2r2_blt.h> +#include "../b2r2_profiler_api.h" + + +#define S32_MAX 2147483647 + + +static int src_format_filter_on = false; +module_param(src_format_filter_on, bool, S_IRUGO | S_IWUSR); +static unsigned int src_format_filter; +module_param(src_format_filter, uint, S_IRUGO | S_IWUSR); + +static int print_blts_on = 0; +module_param(print_blts_on, bool, S_IRUGO | S_IWUSR); +static int use_mpix_per_second_in_print_blts = 1; +module_param(use_mpix_per_second_in_print_blts, bool, S_IRUGO | S_IWUSR); + +static int profiler_stats_on = 1; +module_param(profiler_stats_on, bool, S_IRUGO | S_IWUSR); + +static const unsigned int profiler_stats_blts_used = 400; +static struct { + unsigned long sampling_start_time_jiffies; + + s32 min_mpix_per_second; + struct b2r2_blt_req min_blt_request; + struct b2r2_blt_profiling_info min_blt_profiling_info; + + s32 max_mpix_per_second; + struct b2r2_blt_req max_blt_request; + struct b2r2_blt_profiling_info max_blt_profiling_info; + + s32 accumulated_num_pixels; + s32 accumulated_num_usecs; + + u32 num_blts_done; +} profiler_stats; + + +static s32 nsec_2_usec(const s32 nsec); + +static int is_scale_blt(const struct b2r2_blt_req * const request); +static s32 get_blt_mpix_per_second(const struct b2r2_blt_req * const request, + const struct b2r2_blt_profiling_info * const blt_profiling_info); +static void print_blt(const struct b2r2_blt_req * const request, + const struct b2r2_blt_profiling_info * const blt_profiling_info); + +static s32 get_num_pixels_in_blt(const struct b2r2_blt_req * const request); +static s32 get_mpix_per_second(const s32 num_pixels, const s32 num_usecs); +static void print_profiler_stats(void); +static void reset_profiler_stats(void); +static void do_profiler_stats(const struct b2r2_blt_req * const request, + const struct b2r2_blt_profiling_info * const blt_profiling_info); + +static void blt_done(const struct b2r2_blt_req * const blt, + const s32 request_id, + const struct b2r2_blt_profiling_info * const blt_profiling_info); + + +static struct b2r2_profiler this = { + .blt_done = blt_done, +}; + + +static s32 nsec_2_usec(const s32 nsec) +{ + return nsec / 1000; +} + + +static int is_scale_blt(const struct b2r2_blt_req * const request) +{ + if ((request->transform & B2R2_BLT_TRANSFORM_CCW_ROT_90 && + (request->src_rect.width != + request->dst_rect.height || + request->src_rect.height != + request->dst_rect.width)) || + (!(request->transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) && + (request->src_rect.width != + request->dst_rect.width || + request->src_rect.height != + request->dst_rect.height))) + return 1; + else + return 0; +} + +static s32 get_blt_mpix_per_second(const struct b2r2_blt_req * const request, + const struct b2r2_blt_profiling_info * const blt_profiling_info) +{ + return get_mpix_per_second(get_num_pixels_in_blt(request), + nsec_2_usec(blt_profiling_info->nsec_active_in_cpu + + blt_profiling_info->nsec_active_in_b2r2)); +} + +static void print_blt(const struct b2r2_blt_req * const request, + const struct b2r2_blt_profiling_info * const blt_profiling_info) +{ + char tmp_str[128]; + sprintf(tmp_str, "SF: %#10x, DF: %#10x, F: %#10x, T: %#3x, S: %1i, P: %7i", + request->src_img.fmt, + request->dst_img.fmt, + request->flags, + request->transform, + is_scale_blt(request), + get_num_pixels_in_blt(request)); + if (use_mpix_per_second_in_print_blts) + printk(KERN_ALERT "%s, MPix/s: %3i\n", tmp_str, + get_blt_mpix_per_second(request, blt_profiling_info)); + else + printk(KERN_ALERT "%s, CPU: %10i, B2R2: %10i, Tot: %10i ns\n", + tmp_str, blt_profiling_info->nsec_active_in_cpu, + blt_profiling_info->nsec_active_in_b2r2, + blt_profiling_info->total_time_nsec); +} + + +static s32 get_num_pixels_in_blt(const struct b2r2_blt_req * const request) +{ + s32 num_pixels_in_src = request->src_rect.width * request->src_rect.height; + s32 num_pixels_in_dst = request->dst_rect.width * request->dst_rect.height; + if (request->flags & (B2R2_BLT_FLAG_SOURCE_FILL | + B2R2_BLT_FLAG_SOURCE_FILL_RAW)) + return num_pixels_in_dst; + else + return (num_pixels_in_src + num_pixels_in_dst) / 2; +} + +static s32 get_mpix_per_second(const s32 num_pixels, const s32 num_usecs) +{ + s32 num_pixels_scale_factor = num_pixels != 0 ? + S32_MAX / num_pixels : S32_MAX; + s32 num_usecs_scale_factor = num_usecs != 0 ? + S32_MAX / num_usecs : S32_MAX; + s32 scale_factor = min(num_pixels_scale_factor, num_usecs_scale_factor); + + s32 num_pixels_scaled = num_pixels * scale_factor; + s32 num_usecs_scaled = num_usecs * scale_factor; + + if (num_usecs_scaled < 1000000) + return 0; + + return (num_pixels_scaled / 1000000) / (num_usecs_scaled / 1000000); +} + +static void print_profiler_stats(void) +{ + printk(KERN_ALERT "Min: %3i, Avg: %3i, Max: %3i MPix/s\n", + profiler_stats.min_mpix_per_second, + get_mpix_per_second( + profiler_stats.accumulated_num_pixels, + profiler_stats.accumulated_num_usecs), + profiler_stats.max_mpix_per_second); + printk(KERN_ALERT "Min blit:\n"); + print_blt(&profiler_stats.min_blt_request, + &profiler_stats.min_blt_profiling_info); + printk(KERN_ALERT "Max blit:\n"); + print_blt(&profiler_stats.max_blt_request, + &profiler_stats.max_blt_profiling_info); +} + +static void reset_profiler_stats(void) +{ + profiler_stats.sampling_start_time_jiffies = jiffies; + profiler_stats.min_mpix_per_second = S32_MAX; + profiler_stats.max_mpix_per_second = 0; + profiler_stats.accumulated_num_pixels = 0; + profiler_stats.accumulated_num_usecs = 0; + profiler_stats.num_blts_done = 0; +} + +static void do_profiler_stats(const struct b2r2_blt_req * const request, + const struct b2r2_blt_profiling_info * const blt_profiling_info) +{ + s32 num_pixels_in_blt; + s32 num_usec_blt_took; + s32 blt_mpix_per_second; + + if (time_before(jiffies, profiler_stats.sampling_start_time_jiffies)) + return; + + num_pixels_in_blt = get_num_pixels_in_blt(request); + num_usec_blt_took = nsec_2_usec(blt_profiling_info->nsec_active_in_cpu + + blt_profiling_info->nsec_active_in_b2r2); + blt_mpix_per_second = get_mpix_per_second(num_pixels_in_blt, + num_usec_blt_took); + + if (blt_mpix_per_second <= + profiler_stats.min_mpix_per_second) { + profiler_stats.min_mpix_per_second = blt_mpix_per_second; + memcpy(&profiler_stats.min_blt_request, + request, sizeof(struct b2r2_blt_req)); + memcpy(&profiler_stats.min_blt_profiling_info, + blt_profiling_info, + sizeof(struct b2r2_blt_profiling_info)); + } + + if (blt_mpix_per_second >= profiler_stats.max_mpix_per_second) { + profiler_stats.max_mpix_per_second = blt_mpix_per_second; + memcpy(&profiler_stats.max_blt_request, request, + sizeof(struct b2r2_blt_req)); + memcpy(&profiler_stats.max_blt_profiling_info, + blt_profiling_info, sizeof(struct b2r2_blt_profiling_info)); + } + + profiler_stats.accumulated_num_pixels += num_pixels_in_blt; + profiler_stats.accumulated_num_usecs += num_usec_blt_took; + profiler_stats.num_blts_done++; + + if (profiler_stats.num_blts_done >= profiler_stats_blts_used) { + print_profiler_stats(); + reset_profiler_stats(); + /* The printouts initiated above can disturb the next measurement + so we delay it two seconds to give the printouts a chance to finish. */ + profiler_stats.sampling_start_time_jiffies = jiffies + (2 * HZ); + } +} + +static void blt_done(const struct b2r2_blt_req * const request, + const s32 request_id, + const struct b2r2_blt_profiling_info * const blt_profiling_info) +{ + /* Filters */ + if (src_format_filter_on && request->src_img.fmt != src_format_filter) + return; + + /* Processors */ + if (print_blts_on) + print_blt(request, blt_profiling_info); + + if (profiler_stats_on) + do_profiler_stats(request, blt_profiling_info); +} + + +static int __init b2r2_profiler_init(void) +{ + reset_profiler_stats(); + + return b2r2_register_profiler(&this); +} +module_init(b2r2_profiler_init); + +static void __exit b2r2_profiler_exit(void) +{ + b2r2_unregister_profiler(&this); +} +module_exit(b2r2_profiler_exit); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Johan Mossberg (johan.xx.mossberg@stericsson.com)"); +MODULE_DESCRIPTION("B2R2 Profiler"); diff --git a/drivers/video/b2r2/b2r2_profiler_api.h b/drivers/video/b2r2/b2r2_profiler_api.h new file mode 100644 index 00000000000..5f1f9abbe49 --- /dev/null +++ b/drivers/video/b2r2/b2r2_profiler_api.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 profiling API + * + * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + + +#ifndef _LINUX_VIDEO_B2R2_PROFILER_API_H +#define _LINUX_VIDEO_B2R2_PROFILER_API_H + +#include <video/b2r2_blt.h> + +/** + * struct b2r2_blt_profiling_info - Profiling information for a blit + * + * @nsec_active_in_cpu: The number of nanoseconds the job was active in the CPU. + * This is an approximate value, check out the code for more + * info. + * @nsec_active_in_b2r2: The number of nanoseconds the job was active in B2R2. This + * is an approximate value, check out the code for more info. + * @total_time_nsec: The total time the job took in nano seconds. Includes ideling. + */ +struct b2r2_blt_profiling_info { + s32 nsec_active_in_cpu; + s32 nsec_active_in_b2r2; + s32 total_time_nsec; +}; + +/** + * struct b2r2_profiler - B2R2 profiler. + * + * The callbacks are never run concurrently. No heavy stuff must be done in the + * callbacks as this might adversely affect the B2R2 driver. The callbacks must + * not call the B2R2 profiler API as this will cause a deadlock. If the callbacks + * call into the B2R2 driver care must be taken as deadlock situations can arise. + * + * @blt_done: Called when a blit has finished, timed out or been canceled. + */ +struct b2r2_profiler { + void (*blt_done)(const struct b2r2_blt_req * const request, const s32 request_id, const struct b2r2_blt_profiling_info * const blt_profiling_info); +}; + +/** + * b2r2_register_profiler() - Registers a profiler. + * + * Currently only one profiler can be registered at any given time. + * + * @profiler: The profiler + * + * Returns 0 on success, negative error code on failure + */ +int b2r2_register_profiler(const struct b2r2_profiler * const profiler); + +/** + * b2r2_unregister_profiler() - Unregisters a profiler. + * + * @profiler: The profiler + */ +void b2r2_unregister_profiler(const struct b2r2_profiler * const profiler); + +#endif /* #ifdef _LINUX_VIDEO_B2R2_PROFILER_API_H */ diff --git a/drivers/video/b2r2/b2r2_profiler_socket.c b/drivers/video/b2r2/b2r2_profiler_socket.c new file mode 100644 index 00000000000..ffa7f2870c8 --- /dev/null +++ b/drivers/video/b2r2/b2r2_profiler_socket.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 profiler socket communication + * + * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/semaphore.h> +#include <asm/errno.h> + +#include "b2r2_profiler_api.h" +#include "b2r2_internal.h" + + +/* + * TODO: Call the profiler in a seperate thread and have a circular buffer + * between the B2R2 driver and that thread. That way the profiler can not slow + * down or kill the B2R2 driver. Seems a bit overkill right now as there is + * only one B2R2 profiler and we have full control over it but the situation + * may be different in the future. + */ + + +static const struct b2r2_profiler *b2r2_profiler; +static DEFINE_SEMAPHORE(b2r2_profiler_lock); + + +int b2r2_register_profiler(const struct b2r2_profiler * const profiler) +{ + int return_value; + + return_value = down_interruptible(&b2r2_profiler_lock); + if (return_value != 0) + return return_value; + + if (b2r2_profiler != NULL) { + return_value = -EUSERS; + + goto cleanup; + } + + b2r2_profiler = profiler; + + return_value = 0; + +cleanup: + up(&b2r2_profiler_lock); + + return return_value; +} +EXPORT_SYMBOL(b2r2_register_profiler); + +void b2r2_unregister_profiler(const struct b2r2_profiler * const profiler) +{ + down(&b2r2_profiler_lock); + + if (profiler == b2r2_profiler) + b2r2_profiler = NULL; + + up(&b2r2_profiler_lock); +} +EXPORT_SYMBOL(b2r2_unregister_profiler); + + +bool is_profiler_registered_approx(void) +{ + /* No locking by design, to make it fast, hence the approx */ + if (b2r2_profiler != NULL) + return true; + else + return false; +} + +void b2r2_call_profiler_blt_done(const struct b2r2_blt_request * const request) +{ + int return_value; + struct b2r2_blt_profiling_info blt_profiling_info; + struct b2r2_control *cont = request->instance->control; + + return_value = down_interruptible(&b2r2_profiler_lock); + if (return_value != 0) { + dev_err(cont->dev, + "%s: Failed to acquire semaphore, ret=%i. " + "Lost profiler call!\n", __func__, return_value); + + return; + } + + if (NULL == b2r2_profiler) + goto cleanup; + + blt_profiling_info.nsec_active_in_cpu = request->nsec_active_in_cpu; + blt_profiling_info.nsec_active_in_b2r2 = request->job.nsec_active_in_hw; + blt_profiling_info.total_time_nsec = request->total_time_nsec; + + b2r2_profiler->blt_done(&request->user_req, request->request_id, &blt_profiling_info); + +cleanup: + up(&b2r2_profiler_lock); +} diff --git a/drivers/video/b2r2/b2r2_profiler_socket.h b/drivers/video/b2r2/b2r2_profiler_socket.h new file mode 100644 index 00000000000..80b2c20293f --- /dev/null +++ b/drivers/video/b2r2/b2r2_profiler_socket.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 profiler socket communication + * + * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef _LINUX_VIDEO_B2R2_PROFILER_SOCKET_H +#define _LINUX_VIDEO_B2R2_PROFILER_SOCKET_H + +#include "b2r2_internal.h" + +/* Will give a correct result most of the time but can be wrong */ +bool is_profiler_registered_approx(void); + +void b2r2_call_profiler_blt_done(const struct b2r2_blt_request * const request); + +#endif /* _LINUX_VIDEO_B2R2_PROFILER_SOCKET_H */ diff --git a/drivers/video/b2r2/b2r2_structures.h b/drivers/video/b2r2/b2r2_structures.h new file mode 100644 index 00000000000..99fa7f047d3 --- /dev/null +++ b/drivers/video/b2r2/b2r2_structures.h @@ -0,0 +1,226 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 register struct + * + * Author: Robert Fekete <robert.fekete@stericsson.com> + * Author: Paul Wannback + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + + +#ifndef __B2R2_STRUCTURES_H +#define __B2R2_STRUCTURES_H + +/* C struct view */ +struct b2r2_memory_map { + unsigned char fill0[2304]; + unsigned int BLT_SSBA17; /* @2304 */ + unsigned int BLT_SSBA18; /* @2308 */ + unsigned int BLT_SSBA19; /* @2312 */ + unsigned int BLT_SSBA20; /* @2316 */ + unsigned int BLT_SSBA21; /* @2320 */ + unsigned int BLT_SSBA22; /* @2324 */ + unsigned int BLT_SSBA23; /* @2328 */ + unsigned int BLT_SSBA24; /* @2332 */ + unsigned char fill1[32]; + unsigned int BLT_STBA5; /* @2368 */ + unsigned int BLT_STBA6; /* @2372 */ + unsigned int BLT_STBA7; /* @2376 */ + unsigned int BLT_STBA8; /* @2380 */ + unsigned char fill2[176]; + unsigned int BLT_CTL; /* @2560 */ + unsigned int BLT_ITS; /* @2564 */ + unsigned int BLT_STA1; /* @2568 */ + unsigned char fill3[4]; + unsigned int BLT_SSBA1; /* @2576 */ + unsigned int BLT_SSBA2; /* @2580 */ + unsigned int BLT_SSBA3; /* @2584 */ + unsigned int BLT_SSBA4; /* @2588 */ + unsigned int BLT_SSBA5; /* @2592 */ + unsigned int BLT_SSBA6; /* @2596 */ + unsigned int BLT_SSBA7; /* @2600 */ + unsigned int BLT_SSBA8; /* @2604 */ + unsigned int BLT_STBA1; /* @2608 */ + unsigned int BLT_STBA2; /* @2612 */ + unsigned int BLT_STBA3; /* @2616 */ + unsigned int BLT_STBA4; /* @2620 */ + unsigned int BLT_CQ1_TRIG_IP; /* @2624 */ + unsigned int BLT_CQ1_TRIG_CTL; /* @2628 */ + unsigned int BLT_CQ1_PACE_CTL; /* @2632 */ + unsigned int BLT_CQ1_IP; /* @2636 */ + unsigned int BLT_CQ2_TRIG_IP; /* @2640 */ + unsigned int BLT_CQ2_TRIG_CTL; /* @2644 */ + unsigned int BLT_CQ2_PACE_CTL; /* @2648 */ + unsigned int BLT_CQ2_IP; /* @2652 */ + unsigned int BLT_AQ1_CTL; /* @2656 */ + unsigned int BLT_AQ1_IP; /* @2660 */ + unsigned int BLT_AQ1_LNA; /* @2664 */ + unsigned int BLT_AQ1_STA; /* @2668 */ + unsigned int BLT_AQ2_CTL; /* @2672 */ + unsigned int BLT_AQ2_IP; /* @2676 */ + unsigned int BLT_AQ2_LNA; /* @2680 */ + unsigned int BLT_AQ2_STA; /* @2684 */ + unsigned int BLT_AQ3_CTL; /* @2688 */ + unsigned int BLT_AQ3_IP; /* @2692 */ + unsigned int BLT_AQ3_LNA; /* @2696 */ + unsigned int BLT_AQ3_STA; /* @2700 */ + unsigned int BLT_AQ4_CTL; /* @2704 */ + unsigned int BLT_AQ4_IP; /* @2708 */ + unsigned int BLT_AQ4_LNA; /* @2712 */ + unsigned int BLT_AQ4_STA; /* @2716 */ + unsigned int BLT_SSBA9; /* @2720 */ + unsigned int BLT_SSBA10; /* @2724 */ + unsigned int BLT_SSBA11; /* @2728 */ + unsigned int BLT_SSBA12; /* @2732 */ + unsigned int BLT_SSBA13; /* @2736 */ + unsigned int BLT_SSBA14; /* @2740 */ + unsigned int BLT_SSBA15; /* @2744 */ + unsigned int BLT_SSBA16; /* @2748 */ + unsigned int BLT_SGA1; /* @2752 */ + unsigned int BLT_SGA2; /* @2756 */ + unsigned char fill4[8]; + unsigned int BLT_ITM0; /* @2768 */ + unsigned int BLT_ITM1; /* @2772 */ + unsigned int BLT_ITM2; /* @2776 */ + unsigned int BLT_ITM3; /* @2780 */ + unsigned char fill5[16]; + unsigned int BLT_DFV2; /* @2800 */ + unsigned int BLT_DFV1; /* @2804 */ + unsigned int BLT_PRI; /* @2808 */ + unsigned char fill6[8]; + unsigned int PLUGS1_OP2; /* @2820 */ + unsigned int PLUGS1_CHZ; /* @2824 */ + unsigned int PLUGS1_MSZ; /* @2828 */ + unsigned int PLUGS1_PGZ; /* @2832 */ + unsigned char fill7[16]; + unsigned int PLUGS2_OP2; /* @2852 */ + unsigned int PLUGS2_CHZ; /* @2856 */ + unsigned int PLUGS2_MSZ; /* @2860 */ + unsigned int PLUGS2_PGZ; /* @2864 */ + unsigned char fill8[16]; + unsigned int PLUGS3_OP2; /* @2884 */ + unsigned int PLUGS3_CHZ; /* @2888 */ + unsigned int PLUGS3_MSZ; /* @2892 */ + unsigned int PLUGS3_PGZ; /* @2896 */ + unsigned char fill9[48]; + unsigned int PLUGT_OP2; /* @2948 */ + unsigned int PLUGT_CHZ; /* @2952 */ + unsigned int PLUGT_MSZ; /* @2956 */ + unsigned int PLUGT_PGZ; /* @2960 */ + unsigned char fill10[108]; + unsigned int BLT_NIP; /* @3072 */ + unsigned int BLT_CIC; /* @3076 */ + unsigned int BLT_INS; /* @3080 */ + unsigned int BLT_ACK; /* @3084 */ + unsigned int BLT_TBA; /* @3088 */ + unsigned int BLT_TTY; /* @3092 */ + unsigned int BLT_TXY; /* @3096 */ + unsigned int BLT_TSZ; /* @3100 */ + unsigned int BLT_S1CF; /* @3104 */ + unsigned int BLT_S2CF; /* @3108 */ + unsigned int BLT_S1BA; /* @3112 */ + unsigned int BLT_S1TY; /* @3116 */ + unsigned int BLT_S1XY; /* @3120 */ + unsigned char fill11[4]; + unsigned int BLT_S2BA; /* @3128 */ + unsigned int BLT_S2TY; /* @3132 */ + unsigned int BLT_S2XY; /* @3136 */ + unsigned int BLT_S2SZ; /* @3140 */ + unsigned int BLT_S3BA; /* @3144 */ + unsigned int BLT_S3TY; /* @3148 */ + unsigned int BLT_S3XY; /* @3152 */ + unsigned int BLT_S3SZ; /* @3156 */ + unsigned int BLT_CWO; /* @3160 */ + unsigned int BLT_CWS; /* @3164 */ + unsigned int BLT_CCO; /* @3168 */ + unsigned int BLT_CML; /* @3172 */ + unsigned int BLT_FCTL; /* @3176 */ + unsigned int BLT_PMK; /* @3180 */ + unsigned int BLT_RSF; /* @3184 */ + unsigned int BLT_RZI; /* @3188 */ + unsigned int BLT_HFP; /* @3192 */ + unsigned int BLT_VFP; /* @3196 */ + unsigned int BLT_Y_RSF; /* @3200 */ + unsigned int BLT_Y_RZI; /* @3204 */ + unsigned int BLT_Y_HFP; /* @3208 */ + unsigned int BLT_Y_VFP; /* @3212 */ + unsigned char fill12[16]; + unsigned int BLT_KEY1; /* @3232 */ + unsigned int BLT_KEY2; /* @3236 */ + unsigned char fill13[8]; + unsigned int BLT_SAR; /* @3248 */ + unsigned int BLT_USR; /* @3252 */ + unsigned char fill14[8]; + unsigned int BLT_IVMX0; /* @3264 */ + unsigned int BLT_IVMX1; /* @3268 */ + unsigned int BLT_IVMX2; /* @3272 */ + unsigned int BLT_IVMX3; /* @3276 */ + unsigned int BLT_OVMX0; /* @3280 */ + unsigned int BLT_OVMX1; /* @3284 */ + unsigned int BLT_OVMX2; /* @3288 */ + unsigned int BLT_OVMX3; /* @3292 */ + unsigned char fill15[8]; + unsigned int BLT_VC1R; /* @3304 */ + unsigned char fill16[20]; + unsigned int BLT_Y_HFC0; /* @3328 */ + unsigned int BLT_Y_HFC1; /* @3332 */ + unsigned int BLT_Y_HFC2; /* @3336 */ + unsigned int BLT_Y_HFC3; /* @3340 */ + unsigned int BLT_Y_HFC4; /* @3344 */ + unsigned int BLT_Y_HFC5; /* @3348 */ + unsigned int BLT_Y_HFC6; /* @3352 */ + unsigned int BLT_Y_HFC7; /* @3356 */ + unsigned int BLT_Y_HFC8; /* @3360 */ + unsigned int BLT_Y_HFC9; /* @3364 */ + unsigned int BLT_Y_HFC10; /* @3368 */ + unsigned int BLT_Y_HFC11; /* @3372 */ + unsigned int BLT_Y_HFC12; /* @3376 */ + unsigned int BLT_Y_HFC13; /* @3380 */ + unsigned int BLT_Y_HFC14; /* @3384 */ + unsigned int BLT_Y_HFC15; /* @3388 */ + unsigned char fill17[80]; + unsigned int BLT_Y_VFC0; /* @3472 */ + unsigned int BLT_Y_VFC1; /* @3476 */ + unsigned int BLT_Y_VFC2; /* @3480 */ + unsigned int BLT_Y_VFC3; /* @3484 */ + unsigned int BLT_Y_VFC4; /* @3488 */ + unsigned int BLT_Y_VFC5; /* @3492 */ + unsigned int BLT_Y_VFC6; /* @3496 */ + unsigned int BLT_Y_VFC7; /* @3500 */ + unsigned int BLT_Y_VFC8; /* @3504 */ + unsigned int BLT_Y_VFC9; /* @3508 */ + unsigned char fill18[72]; + unsigned int BLT_HFC0; /* @3584 */ + unsigned int BLT_HFC1; /* @3588 */ + unsigned int BLT_HFC2; /* @3592 */ + unsigned int BLT_HFC3; /* @3596 */ + unsigned int BLT_HFC4; /* @3600 */ + unsigned int BLT_HFC5; /* @3604 */ + unsigned int BLT_HFC6; /* @3608 */ + unsigned int BLT_HFC7; /* @3612 */ + unsigned int BLT_HFC8; /* @3616 */ + unsigned int BLT_HFC9; /* @3620 */ + unsigned int BLT_HFC10; /* @3624 */ + unsigned int BLT_HFC11; /* @3628 */ + unsigned int BLT_HFC12; /* @3632 */ + unsigned int BLT_HFC13; /* @3636 */ + unsigned int BLT_HFC14; /* @3640 */ + unsigned int BLT_HFC15; /* @3644 */ + unsigned char fill19[80]; + unsigned int BLT_VFC0; /* @3728 */ + unsigned int BLT_VFC1; /* @3732 */ + unsigned int BLT_VFC2; /* @3736 */ + unsigned int BLT_VFC3; /* @3740 */ + unsigned int BLT_VFC4; /* @3744 */ + unsigned int BLT_VFC5; /* @3748 */ + unsigned int BLT_VFC6; /* @3752 */ + unsigned int BLT_VFC7; /* @3756 */ + unsigned int BLT_VFC8; /* @3760 */ + unsigned int BLT_VFC9; /* @3764 */ +}; + +#endif /* !defined(__B2R2_STRUCTURES_H) */ + diff --git a/drivers/video/b2r2/b2r2_timing.c b/drivers/video/b2r2/b2r2_timing.c new file mode 100644 index 00000000000..4f3e2b8b042 --- /dev/null +++ b/drivers/video/b2r2/b2r2_timing.c @@ -0,0 +1,22 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 timing + * + * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/time.h> + + +u32 b2r2_get_curr_nsec(void) +{ + struct timespec ts; + + getrawmonotonic(&ts); + + return (u32)timespec_to_ns(&ts); +} diff --git a/drivers/video/b2r2/b2r2_timing.h b/drivers/video/b2r2/b2r2_timing.h new file mode 100644 index 00000000000..e87113c0ec9 --- /dev/null +++ b/drivers/video/b2r2/b2r2_timing.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 timing + * + * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef _LINUX_DRIVERS_VIDEO_B2R2_TIMING_H_ +#define _LINUX_DRIVERS_VIDEO_B2R2_TIMING_H_ + +/** + * b2r2_get_curr_nsec() - Return the current nanosecond. Notice that the value + * wraps when the u32 limit is reached. + * + */ +u32 b2r2_get_curr_nsec(void); + +#endif /* _LINUX_DRIVERS_VIDEO_B2R2_TIMING_H_ */ diff --git a/drivers/video/b2r2/b2r2_utils.c b/drivers/video/b2r2/b2r2_utils.c new file mode 100644 index 00000000000..3df7a272211 --- /dev/null +++ b/drivers/video/b2r2/b2r2_utils.c @@ -0,0 +1,633 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 utils + * + * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> + +#include <video/b2r2_blt.h> + +#include "b2r2_utils.h" +#include "b2r2_debug.h" +#include "b2r2_internal.h" + +const s32 b2r2_s32_max = 2147483647; + + +/** + * calculate_scale_factor() - calculates the scale factor between the given + * values + */ +int calculate_scale_factor(struct b2r2_control *cont, + u32 from, u32 to, u16 *sf_out) +{ + int ret; + u32 sf; + + b2r2_log_info(cont->dev, "%s\n", __func__); + + if (to == from) { + *sf_out = 1 << 10; + return 0; + } else if (to == 0) { + b2r2_log_err(cont->dev, "%s: To is 0!\n", __func__); + BUG_ON(1); + } + + sf = (from << 10) / to; + + if ((sf & 0xffff0000) != 0) { + /* Overflow error */ + b2r2_log_warn(cont->dev, "%s: " + "Scale factor too large\n", __func__); + ret = -EINVAL; + goto error; + } else if (sf == 0) { + b2r2_log_warn(cont->dev, "%s: " + "Scale factor too small\n", __func__); + ret = -EINVAL; + goto error; + } + + *sf_out = (u16)sf; + + b2r2_log_info(cont->dev, "%s exit\n", __func__); + + return 0; + +error: + b2r2_log_warn(cont->dev, "%s: Exit...\n", __func__); + return ret; +} + +void b2r2_get_img_bounding_rect(struct b2r2_blt_img *img, + struct b2r2_blt_rect *bounding_rect) +{ + bounding_rect->x = 0; + bounding_rect->y = 0; + bounding_rect->width = img->width; + bounding_rect->height = img->height; +} + + +bool b2r2_is_zero_area_rect(struct b2r2_blt_rect *rect) +{ + return rect->width == 0 || rect->height == 0; +} + +bool b2r2_is_rect_inside_rect(struct b2r2_blt_rect *rect1, + struct b2r2_blt_rect *rect2) +{ + return rect1->x >= rect2->x && + rect1->y >= rect2->y && + rect1->x + rect1->width <= rect2->x + rect2->width && + rect1->y + rect1->height <= rect2->y + rect2->height; +} + +bool b2r2_is_rect_gte_rect(struct b2r2_blt_rect *rect1, + struct b2r2_blt_rect *rect2) +{ + return rect1->width >= rect2->width && + rect1->height >= rect2->height; +} + +void b2r2_intersect_rects(struct b2r2_blt_rect *rect1, + struct b2r2_blt_rect *rect2, struct b2r2_blt_rect *intersection) +{ + struct b2r2_blt_rect tmp_rect; + + tmp_rect.x = max(rect1->x, rect2->x); + tmp_rect.y = max(rect1->y, rect2->y); + tmp_rect.width = min(rect1->x + rect1->width, rect2->x + rect2->width) + - tmp_rect.x; + if (tmp_rect.width < 0) + tmp_rect.width = 0; + tmp_rect.height = + min(rect1->y + rect1->height, rect2->y + rect2->height) - + tmp_rect.y; + if (tmp_rect.height < 0) + tmp_rect.height = 0; + + *intersection = tmp_rect; +} + +/* + * Calculate new rectangles for the supplied + * request, so that clipping to destination imaage + * can be avoided. + * Essentially, the new destination rectangle is + * defined inside the old one. Given the transform + * and scaling, one has to calculate which part of + * the old source rectangle corresponds to + * to the new part of old destination rectangle. + */ +void b2r2_trim_rects(struct b2r2_control *cont, + const struct b2r2_blt_req *req, + struct b2r2_blt_rect *new_bg_rect, + struct b2r2_blt_rect *new_dst_rect, + struct b2r2_blt_rect *new_src_rect) +{ + enum b2r2_blt_transform transform = req->transform; + struct b2r2_blt_rect *old_src_rect = + (struct b2r2_blt_rect *) &req->src_rect; + struct b2r2_blt_rect *old_dst_rect = + (struct b2r2_blt_rect *) &req->dst_rect; + struct b2r2_blt_rect *old_bg_rect = + (struct b2r2_blt_rect *) &req->bg_rect; + struct b2r2_blt_rect dst_img_bounds; + s32 src_x = 0; + s32 src_y = 0; + s32 src_w = 0; + s32 src_h = 0; + s32 dx = 0; + s32 dy = 0; + s16 hsf; + s16 vsf; + + b2r2_log_info(cont->dev, + "%s\nold_dst_rect(x,y,w,h)=(%d, %d, %d, %d)\n", __func__, + old_dst_rect->x, old_dst_rect->y, + old_dst_rect->width, old_dst_rect->height); + b2r2_log_info(cont->dev, + "%s\nold_src_rect(x,y,w,h)=(%d, %d, %d, %d)\n", __func__, + old_src_rect->x, old_src_rect->y, + old_src_rect->width, old_src_rect->height); + + b2r2_get_img_bounding_rect((struct b2r2_blt_img *) &req->dst_img, + &dst_img_bounds); + + /* dst_rect inside dst_img, no clipping necessary */ + if (b2r2_is_rect_inside_rect(old_dst_rect, &dst_img_bounds)) + goto keep_rects; + + b2r2_intersect_rects(old_dst_rect, &dst_img_bounds, new_dst_rect); + b2r2_log_info(cont->dev, + "%s\nnew_dst_rect(x,y,w,h)=(%d, %d, %d, %d)\n", __func__, + new_dst_rect->x, new_dst_rect->y, + new_dst_rect->width, new_dst_rect->height); + + /* dst_rect completely outside, leave it to validation */ + if (new_dst_rect->width == 0 || new_dst_rect->height == 0) + goto keep_rects; + + dx = new_dst_rect->x - old_dst_rect->x; + dy = new_dst_rect->y - old_dst_rect->y; + + if (transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) { + int res = 0; + res = calculate_scale_factor(cont, old_src_rect->width, + old_dst_rect->height, &hsf); + /* invalid dimensions, leave them to validation */ + if (res < 0) + goto keep_rects; + + res = calculate_scale_factor(cont, old_src_rect->height, + old_dst_rect->width, &vsf); + if (res < 0) + goto keep_rects; + + /* + * After applying the inverse transform + * for 90 degree rotation, the top-left corner + * becomes top-right. + * src_rect origin is defined as top-left, + * so a translation between dst and src + * coordinate spaces is necessary. + */ + src_x = (old_src_rect->width << 10) - + hsf * (dy + new_dst_rect->height); + src_y = dx * vsf; + src_w = new_dst_rect->height * hsf; + src_h = new_dst_rect->width * vsf; + } else { + int res = 0; + res = calculate_scale_factor(cont, old_src_rect->width, + old_dst_rect->width, &hsf); + if (res < 0) + goto keep_rects; + + res = calculate_scale_factor(cont, old_src_rect->height, + old_dst_rect->height, &vsf); + if (res < 0) + goto keep_rects; + + src_x = dx * hsf; + src_y = dy * vsf; + src_w = new_dst_rect->width * hsf; + src_h = new_dst_rect->height * vsf; + } + + /* + * src_w must contain all the pixels that contribute + * to a particular destination rectangle. + * ((x + 0x3ff) >> 10) is equivalent to ceiling(x), + * expressed in 6.10 fixed point format. + * Every destination rectangle, maps to a certain area in the source + * rectangle. The area in source will most likely not be a rectangle + * with exact integer dimensions whenever arbitrary scaling is involved. + * Consider the following example. + * Suppose, that width of the current destination rectangle maps + * to 1.7 pixels in source, starting at x == 5.4, as calculated + * using the scaling factor. + * This means that while the destination rectangle is written, + * the source should be read from x == 5.4 up to x == 5.4 + 1.7 == 7.1 + * Consequently, color from 3 pixels (x == 5, 6 and 7) + * needs to be read from source. + * The formula below the comment yields: + * ceil(0.4 + 1.7) == ceil(2.1) == 3 + * (src_x & 0x3ff) is the fractional part of src_x, + * which is expressed in 6.10 fixed point format. + * Thus, width of the source area should be 3 pixels wide, + * starting at x == 5. + */ + src_w = ((src_x & 0x3ff) + src_w + 0x3ff) >> 10; + src_h = ((src_y & 0x3ff) + src_h + 0x3ff) >> 10; + + src_x >>= 10; + src_y >>= 10; + + if (transform & B2R2_BLT_TRANSFORM_FLIP_H) + src_x = old_src_rect->width - src_x - src_w; + + if (transform & B2R2_BLT_TRANSFORM_FLIP_V) + src_y = old_src_rect->height - src_y - src_h; + + /* + * Translate the src_rect coordinates into true + * src_buffer coordinates. + */ + src_x += old_src_rect->x; + src_y += old_src_rect->y; + + new_src_rect->x = src_x; + new_src_rect->y = src_y; + new_src_rect->width = src_w; + new_src_rect->height = src_h; + + b2r2_log_info(cont->dev, + "%s\nnew_src_rect(x,y,w,h)=(%d, %d, %d, %d)\n", __func__, + new_src_rect->x, new_src_rect->y, + new_src_rect->width, new_src_rect->height); + + if (req->flags & B2R2_BLT_FLAG_BG_BLEND) { + /* Modify bg_rect in the same way as dst_rect */ + s32 dw = new_dst_rect->width - old_dst_rect->width; + s32 dh = new_dst_rect->height - old_dst_rect->height; + b2r2_log_info(cont->dev, + "%s\nold bg_rect(x,y,w,h)=(%d, %d, %d, %d)\n", + __func__, old_bg_rect->x, old_bg_rect->y, + old_bg_rect->width, old_bg_rect->height); + new_bg_rect->x = old_bg_rect->x + dx; + new_bg_rect->y = old_bg_rect->y + dy; + new_bg_rect->width = old_bg_rect->width + dw; + new_bg_rect->height = old_bg_rect->height + dh; + b2r2_log_info(cont->dev, + "%s\nnew bg_rect(x,y,w,h)=(%d, %d, %d, %d)\n", + __func__, new_bg_rect->x, new_bg_rect->y, + new_bg_rect->width, new_bg_rect->height); + } + return; +keep_rects: + /* + * Recalculation was not possible, or not necessary. + * Do not change anything, leave it to validation. + */ + *new_src_rect = *old_src_rect; + *new_dst_rect = *old_dst_rect; + *new_bg_rect = *old_bg_rect; + b2r2_log_info(cont->dev, "%s original rectangles preserved.\n", __func__); + return; +} + +int b2r2_get_fmt_bpp(struct b2r2_control *cont, enum b2r2_blt_fmt fmt) +{ + /* + * Currently this function is not used that often but if that changes a + * lookup table could make it a lot faster. + */ + switch (fmt) { + case B2R2_BLT_FMT_1_BIT_A1: + return 1; + + case B2R2_BLT_FMT_8_BIT_A8: + return 8; + + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + return 12; + + case B2R2_BLT_FMT_16_BIT_ARGB4444: + case B2R2_BLT_FMT_16_BIT_ARGB1555: + case B2R2_BLT_FMT_16_BIT_RGB565: + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + return 16; + + case B2R2_BLT_FMT_24_BIT_RGB888: + case B2R2_BLT_FMT_24_BIT_ARGB8565: + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + return 24; + + case B2R2_BLT_FMT_32_BIT_ARGB8888: + case B2R2_BLT_FMT_32_BIT_ABGR8888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + return 32; + + default: + b2r2_log_err(cont->dev, + "%s: Internal error! Format %#x not recognized.\n", + __func__, fmt); + return 32; + } +} + +int b2r2_get_fmt_y_bpp(struct b2r2_control *cont, enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + return 8; + + default: + b2r2_log_err(cont->dev, + "%s: Internal error! Non YCbCr format supplied.\n", + __func__); + return 8; + } +} + + +bool b2r2_is_single_plane_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_1_BIT_A1: + case B2R2_BLT_FMT_8_BIT_A8: + case B2R2_BLT_FMT_16_BIT_ARGB4444: + case B2R2_BLT_FMT_16_BIT_ARGB1555: + case B2R2_BLT_FMT_16_BIT_RGB565: + case B2R2_BLT_FMT_24_BIT_RGB888: + case B2R2_BLT_FMT_24_BIT_ARGB8565: + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_ARGB8888: + case B2R2_BLT_FMT_32_BIT_ABGR8888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + return true; + + default: + return false; + } +} + +bool b2r2_is_independent_pixel_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_1_BIT_A1: + case B2R2_BLT_FMT_8_BIT_A8: + case B2R2_BLT_FMT_16_BIT_ARGB4444: + case B2R2_BLT_FMT_16_BIT_ARGB1555: + case B2R2_BLT_FMT_16_BIT_RGB565: + case B2R2_BLT_FMT_24_BIT_RGB888: + case B2R2_BLT_FMT_24_BIT_ARGB8565: + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_ARGB8888: + case B2R2_BLT_FMT_32_BIT_ABGR8888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + return true; + + default: + return false; + } +} + +bool b2r2_is_ycbcri_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_24_BIT_VUY888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + return true; + + default: + return false; + } +} + +bool b2r2_is_ycbcrsp_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + return true; + + default: + return false; + } +} + +bool b2r2_is_ycbcrp_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + return true; + + default: + return false; + } +} + +bool b2r2_is_ycbcr420_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + return true; + + default: + return false; + } +} + +bool b2r2_is_ycbcr422_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_Y_CB_Y_CR: + case B2R2_BLT_FMT_CB_Y_CR_Y: + case B2R2_BLT_FMT_YUV422_PACKED_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + return true; + + default: + return false; + } +} + +bool b2r2_is_ycbcr444_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_YUV444_PACKED_PLANAR: + case B2R2_BLT_FMT_32_BIT_AYUV8888: + case B2R2_BLT_FMT_24_BIT_YUV888: + case B2R2_BLT_FMT_32_BIT_VUYA8888: + case B2R2_BLT_FMT_24_BIT_VUY888: + return true; + + default: + return false; + } +} + +bool b2r2_is_mb_fmt(enum b2r2_blt_fmt fmt) +{ + switch (fmt) { + case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: + case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: + return true; + + default: + return false; + } +} + +u32 b2r2_calc_pitch_from_width(struct b2r2_control *cont, + s32 width, enum b2r2_blt_fmt fmt) +{ + if (b2r2_is_single_plane_fmt(fmt)) { + return (u32)b2r2_div_round_up(width * + b2r2_get_fmt_bpp(cont, fmt), 8); + } else if (b2r2_is_ycbcrsp_fmt(fmt) || b2r2_is_ycbcrp_fmt(fmt)) { + return (u32)b2r2_div_round_up(width * + b2r2_get_fmt_y_bpp(cont, fmt), 8); + } else { + b2r2_log_err(cont->dev, "%s: Internal error! " + "Pitchless format supplied.\n", + __func__); + return 0; + } +} + +u32 b2r2_get_img_pitch(struct b2r2_control *cont, struct b2r2_blt_img *img) +{ + if (img->pitch != 0) + return img->pitch; + else + return b2r2_calc_pitch_from_width(cont, img->width, img->fmt); +} + +s32 b2r2_get_img_size(struct b2r2_control *cont, struct b2r2_blt_img *img) +{ + if (b2r2_is_single_plane_fmt(img->fmt)) { + return (s32)b2r2_get_img_pitch(cont, img) * img->height; + } else if (b2r2_is_ycbcrsp_fmt(img->fmt) || + b2r2_is_ycbcrp_fmt(img->fmt)) { + s32 y_plane_size; + + y_plane_size = (s32)b2r2_get_img_pitch(cont, img) * img->height; + + if (b2r2_is_ycbcr420_fmt(img->fmt)) { + return y_plane_size + y_plane_size / 2; + } else if (b2r2_is_ycbcr422_fmt(img->fmt)) { + return y_plane_size * 2; + } else if (b2r2_is_ycbcr444_fmt(img->fmt)) { + return y_plane_size * 3; + } else { + b2r2_log_err(cont->dev, "%s: Internal error!" + " Format %#x not recognized.\n", + __func__, img->fmt); + return 0; + } + } else if (b2r2_is_mb_fmt(img->fmt)) { + return (img->width * img->height * + b2r2_get_fmt_bpp(cont, img->fmt)) / 8; + } else { + b2r2_log_err(cont->dev, "%s: Internal error! " + "Format %#x not recognized.\n", + __func__, img->fmt); + return 0; + } +} + + +s32 b2r2_div_round_up(s32 dividend, s32 divisor) +{ + s32 quotient = dividend / divisor; + if (dividend % divisor != 0) + quotient++; + + return quotient; +} + +bool b2r2_is_aligned(s32 value, s32 alignment) +{ + return value % alignment == 0; +} + +s32 b2r2_align_up(s32 value, s32 alignment) +{ + s32 remainder = abs(value) % abs(alignment); + s32 value_to_add; + + if (remainder > 0) { + if (value >= 0) + value_to_add = alignment - remainder; + else + value_to_add = remainder; + } else { + value_to_add = 0; + } + + return value + value_to_add; +} diff --git a/drivers/video/b2r2/b2r2_utils.h b/drivers/video/b2r2/b2r2_utils.h new file mode 100644 index 00000000000..0516447b42f --- /dev/null +++ b/drivers/video/b2r2/b2r2_utils.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 utils + * + * Author: Johan Mossberg <johan.xx.mossberg@stericsson.com> for ST-Ericsson + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef _LINUX_DRIVERS_VIDEO_B2R2_UTILS_H_ +#define _LINUX_DRIVERS_VIDEO_B2R2_UTILS_H_ + +#include <video/b2r2_blt.h> + +#include "b2r2_internal.h" + +extern const s32 b2r2_s32_max; + +int calculate_scale_factor(struct b2r2_control *cont, + u32 from, u32 to, u16 *sf_out); +void b2r2_get_img_bounding_rect(struct b2r2_blt_img *img, + struct b2r2_blt_rect *bounding_rect); + +bool b2r2_is_zero_area_rect(struct b2r2_blt_rect *rect); +bool b2r2_is_rect_inside_rect(struct b2r2_blt_rect *rect1, + struct b2r2_blt_rect *rect2); +bool b2r2_is_rect_gte_rect(struct b2r2_blt_rect *rect1, + struct b2r2_blt_rect *rect2); +void b2r2_intersect_rects(struct b2r2_blt_rect *rect1, + struct b2r2_blt_rect *rect2, + struct b2r2_blt_rect *intersection); +void b2r2_trim_rects(struct b2r2_control *cont, + const struct b2r2_blt_req *req, + struct b2r2_blt_rect *new_bg_rect, + struct b2r2_blt_rect *new_dst_rect, + struct b2r2_blt_rect *new_src_rect); + +int b2r2_get_fmt_bpp(struct b2r2_control *cont, enum b2r2_blt_fmt fmt); +int b2r2_get_fmt_y_bpp(struct b2r2_control *cont, enum b2r2_blt_fmt fmt); + +bool b2r2_is_single_plane_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_independent_pixel_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_ycbcri_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_ycbcrsp_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_ycbcrp_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_ycbcr420_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_ycbcr422_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_ycbcr444_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_mb_fmt(enum b2r2_blt_fmt fmt); + +/* + * Rounds up if an invalid width causes the pitch to be non byte aligned. + */ +u32 b2r2_calc_pitch_from_width(struct b2r2_control *cont, + s32 width, enum b2r2_blt_fmt fmt); +u32 b2r2_get_img_pitch(struct b2r2_control *cont, + struct b2r2_blt_img *img); +s32 b2r2_get_img_size(struct b2r2_control *cont, + struct b2r2_blt_img *img); + +s32 b2r2_div_round_up(s32 dividend, s32 divisor); +bool b2r2_is_aligned(s32 value, s32 alignment); +s32 b2r2_align_up(s32 value, s32 alignment); + +#endif diff --git a/drivers/video/mcde/Kconfig b/drivers/video/mcde/Kconfig new file mode 100644 index 00000000000..cb88a66d370 --- /dev/null +++ b/drivers/video/mcde/Kconfig @@ -0,0 +1,96 @@ +config FB_MCDE + tristate "MCDE support" + depends on FB + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS + select HWMEM + ---help--- + This enables support for MCDE based frame buffer driver. + + Please read the file <file:Documentation/fb/mcde.txt> + +config FB_MCDE_DEBUG + bool "MCDE debug messages" + depends on FB_MCDE + ---help--- + Say Y here if you want the MCDE driver to output debug messages + +config FB_MCDE_VDEBUG + bool "MCDE verbose debug messages" + depends on FB_MCDE_DEBUG + ---help--- + Say Y here if you want the MCDE driver to output more debug messages + +config MCDE_FB_AVOID_REALLOC + bool "MCDE early allocate framebuffer" + default n + depends on FB_MCDE + ---help--- + If you say Y here maximum frame buffer size is allocated and + used for all resolutions. If you say N here, the frame buffer is + reallocated when resolution is changed. This reallocation might + fail because of fragmented memory. Note that this memory will + never be deallocated, while the MCDE framebuffer is used. + +config MCDE_DISPLAY_DSI + bool "Support for DSI displays within MCDE" + depends on FB_MCDE + default y + +menu "MCDE DSI displays" + depends on MCDE_DISPLAY_DSI + +config MCDE_DISPLAY_GENERIC_DSI + tristate "Generic DSI display driver" + +config MCDE_DISPLAY_SAMSUNG_S6D16D0 + bool "Samsung S6D16D0 DSI display driver" + ---help--- + Say Y if you have a TPO Taal or Blackpearl display panel. + +config MCDE_DISPLAY_SONY_ACX424AKP_DSI + tristate "Sony acx424akp DSI display driver" + +config MCDE_DISPLAY_AV8100 + tristate "AV8100 HDMI/CVBS display driver" + select AV8100 + +config MCDE_DISPLAY_HDMI_FB_AUTO_CREATE + bool "HDMI_FB_AUTO_CREATE" + default y + depends on MCDE_DISPLAY_AV8100 + ---help--- + Say Y if you want the HDMI frame buffer to be created on start + Say N if you want the HDMI frame buffer to be created when HDMI + cable is plugged (needs user space HDMIservice) + +endmenu + +config MCDE_DISPLAY_DPI + bool "Support for DPI displays within MCDE" + depends on FB_MCDE + default n + ---help--- + Add this option to choose which DPI display driver for MCDE to include + + DPI (Display Pixel Interface) is a MIPI Alliance standard used for + active-matrix LCDs. The DPI uses parallel data lines. + +menu "MCDE DPI displays" + depends on MCDE_DISPLAY_DPI + +config MCDE_DISPLAY_VUIB500_DPI + tristate "DPI display driver for the VUIB500 board" + ---help--- + The VUIB500 is an ST-Ericsson user interface board. + +endmenu + +config MCDE_DISPLAY_AB8500_DENC + tristate "AB8500 CVBS display driver" + depends on FB_MCDE + select AB8500_DENC + + diff --git a/drivers/video/mcde/Makefile b/drivers/video/mcde/Makefile new file mode 100644 index 00000000000..82a78c2542a --- /dev/null +++ b/drivers/video/mcde/Makefile @@ -0,0 +1,23 @@ +mcde-objs += mcde_mod.o +mcde-objs += mcde_hw.o +mcde-objs += mcde_dss.o +mcde-objs += mcde_display.o +mcde-objs += mcde_bus.o +mcde-objs += mcde_fb.o +mcde-objs += mcde_debugfs.o +obj-$(CONFIG_FB_MCDE) += mcde.o + +obj-$(CONFIG_MCDE_DISPLAY_GENERIC_DSI) += display-generic_dsi.o +obj-$(CONFIG_MCDE_DISPLAY_SAMSUNG_S6D16D0) += display-samsung_s6d16d0.o +obj-$(CONFIG_MCDE_DISPLAY_SONY_ACX424AKP_DSI) += display-sony_acx424akp_dsi.o +obj-$(CONFIG_MCDE_DISPLAY_VUIB500_DPI) += display-vuib500-dpi.o +obj-$(CONFIG_MCDE_DISPLAY_AB8500_DENC) += display-ab8500.o +obj-$(CONFIG_MCDE_DISPLAY_AV8100) += display-av8100.o +obj-$(CONFIG_DISPLAY_FICTIVE) += display-fictive.o + +ifdef CONFIG_FB_MCDE_DEBUG +EXTRA_CFLAGS += -DDEBUG +endif +ifdef CONFIG_FB_MCDE_VDEBUG +EXTRA_CFLAGS += -DVERBOSE_DEBUG +endif diff --git a/drivers/video/mcde/display-ab8500.c b/drivers/video/mcde/display-ab8500.c new file mode 100644 index 00000000000..a761a5eec80 --- /dev/null +++ b/drivers/video/mcde/display-ab8500.c @@ -0,0 +1,494 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * AB8500 display driver + * + * Author: Marcel Tunnissen <marcel.tuennissen@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/mfd/ab8500/denc.h> +#include <video/mcde_display.h> +#include <video/mcde_display-ab8500.h> + +#define AB8500_DISP_TRACE dev_dbg(&ddev->dev, "%s\n", __func__) + +#define SDTV_PIXCLOCK 37037 + +/* + * PAL: + * Total nr of active lines: 576 + * Total nr of blanking lines: 49 + * total: 625 + */ +#define PAL_HBP 132 +#define PAL_HFP 12 +#define PAL_VBP_FIELD_1 22 +#define PAL_VBP_FIELD_2 23 +#define PAL_VFP_FIELD_1 2 +#define PAL_VFP_FIELD_2 2 + +/* + * NTSC (ITU-R BT.470-5): + * Total nr of active lines: 486 + * Total nr of blanking lines: 39 + * total: 525 + */ +#define NTSC_ORG_HBP 122 +#define NTSC_ORG_HFP 16 +#define NTSC_ORG_VBP_FIELD_1 16 +#define NTSC_ORG_VBP_FIELD_2 17 +#define NTSC_ORG_VFP_FIELD_1 3 +#define NTSC_ORG_VFP_FIELD_2 3 + +/* + * NTSC (DV variant): + * Total nr of active lines: 480 + * Total nr of blanking lines: 45 + * total: 525 + */ +#define NTSC_HBP 122 +#define NTSC_HFP 16 +#define NTSC_VBP_FIELD_1 19 +#define NTSC_VBP_FIELD_2 20 +#define NTSC_VFP_FIELD_1 3 +#define NTSC_VFP_FIELD_2 3 + +struct display_driver_data { + struct ab8500_denc_conf denc_conf; + struct platform_device *denc_dev; + int nr_regulators; + struct regulator **regulator; +}; + +static int try_video_mode(struct mcde_display_device *ddev, + struct mcde_video_mode *video_mode); +static int set_video_mode(struct mcde_display_device *ddev, + struct mcde_video_mode *video_mode); +static int set_power_mode(struct mcde_display_device *ddev, + enum mcde_display_power_mode power_mode); +static int on_first_update(struct mcde_display_device *ddev); +static int display_update(struct mcde_display_device *ddev, + bool tripple_buffer); + +static int __devinit ab8500_probe(struct mcde_display_device *ddev) +{ + int ret = 0; + int i; + struct ab8500_display_platform_data *pdata = ddev->dev.platform_data; + struct display_driver_data *driver_data; + + AB8500_DISP_TRACE; + + if (pdata == NULL) { + dev_err(&ddev->dev, "%s:Platform data missing\n", __func__); + return -EINVAL; + } + if (ddev->port->type != MCDE_PORTTYPE_DPI) { + dev_err(&ddev->dev, "%s:Invalid port type %d\n", __func__, + ddev->port->type); + return -EINVAL; + } + + driver_data = (struct display_driver_data *) + kzalloc(sizeof(struct display_driver_data), GFP_KERNEL); + if (!driver_data) { + dev_err(&ddev->dev, "Failed to allocate driver data\n"); + return -ENOMEM; + } + driver_data->denc_dev = ab8500_denc_get_device(); + if (!driver_data->denc_dev) { + dev_err(&ddev->dev, "Failed to get DENC device\n"); + ret = -ENODEV; + goto dev_get_failed; + } + + driver_data->regulator = kzalloc(pdata->nr_regulators * + sizeof(struct regulator *), GFP_KERNEL); + if (!driver_data->regulator) { + dev_err(&ddev->dev, "Failed to allocate regulator list\n"); + ret = -ENOMEM; + goto reg_alloc_failed; + } + for (i = 0; i < pdata->nr_regulators; i++) { + driver_data->regulator[i] = regulator_get(&ddev->dev, + pdata->regulator_id[i]); + if (IS_ERR(driver_data->regulator[i])) { + ret = PTR_ERR(driver_data->regulator[i]); + dev_warn(&ddev->dev, "%s:Failed to get regulator %s\n", + __func__, pdata->regulator_id[i]); + goto regulator_get_failed; + } + } + driver_data->nr_regulators = pdata->nr_regulators; + + dev_set_drvdata(&ddev->dev, driver_data); + + ddev->try_video_mode = try_video_mode; + ddev->set_video_mode = set_video_mode; + ddev->set_power_mode = set_power_mode; + ddev->on_first_update = on_first_update; + ddev->update = display_update; + + return 0; + +regulator_get_failed: + for (i--; i >= 0; i--) + regulator_put(driver_data->regulator[i]); + kfree(driver_data->regulator); + driver_data->regulator = NULL; +reg_alloc_failed: + ab8500_denc_put_device(driver_data->denc_dev); +dev_get_failed: + kfree(driver_data); + return ret; +} + +static int __devexit ab8500_remove(struct mcde_display_device *ddev) +{ + struct display_driver_data *driver_data = dev_get_drvdata(&ddev->dev); + AB8500_DISP_TRACE; + + ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF); + + if (driver_data->regulator) { + int i; + for (i = driver_data->nr_regulators - 1; i >= 0; i--) + regulator_put(driver_data->regulator[i]); + kfree(driver_data->regulator); + driver_data->regulator = NULL; + driver_data->nr_regulators = 0; + } + ab8500_denc_put_device(driver_data->denc_dev); + kfree(driver_data); + return 0; +} + +static int ab8500_resume(struct mcde_display_device *ddev) +{ + int ret = 0; + AB8500_DISP_TRACE; + + ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY); + if (ret < 0) + dev_warn(&ddev->dev, "%s: Failed to resume display\n", + __func__); + + return ret; +} + +static int ab8500_suspend(struct mcde_display_device *ddev, pm_message_t state) +{ + int ret = 0; + AB8500_DISP_TRACE; + + ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF); + if (ret < 0) + dev_warn(&ddev->dev, "%s: Failed to suspend display\n", + __func__); + + return ret; +} + + +static struct mcde_display_driver ab8500_driver = { + .probe = ab8500_probe, + .remove = ab8500_remove, + .suspend = ab8500_suspend, + .resume = ab8500_resume, + .driver = { + .name = "mcde_tv_ab8500", + }, +}; + +static void print_vmode(struct mcde_video_mode *vmode) +{ + pr_debug("resolution: %dx%d\n", vmode->xres, vmode->yres); + pr_debug(" pixclock: %d\n", vmode->pixclock); + pr_debug(" hbp: %d\n", vmode->hbp); + pr_debug(" hfp: %d\n", vmode->hfp); + pr_debug(" vbp: %d\n", vmode->vbp); + pr_debug(" vfp: %d\n", vmode->vfp); + pr_debug("interlaced: %s\n", vmode->interlaced ? "true" : "false"); +} + +static int try_video_mode( + struct mcde_display_device *ddev, struct mcde_video_mode *video_mode) +{ + AB8500_DISP_TRACE; + + if (ddev == NULL || video_mode == NULL) { + dev_warn(&ddev->dev, "%s:ddev = NULL or video_mode = NULL\n", + __func__); + return -EINVAL; + } + + if (video_mode->xres != 720) { + dev_warn(&ddev->dev, + "%s:Failed to find video mode x=%d, y=%d\n", + __func__, video_mode->xres, video_mode->yres); + return -EINVAL; + } + + /* TODO: move this part to MCDE: mcde_dss_try_video_mode? */ + /* check for PAL */ + switch (video_mode->yres) { + case 576: + /* set including SAV/EAV: */ + video_mode->hbp = PAL_HBP; + video_mode->hfp = PAL_HFP; + video_mode->vbp = PAL_VBP_FIELD_1 + PAL_VBP_FIELD_2; + video_mode->vfp = PAL_VFP_FIELD_1 + PAL_VFP_FIELD_2; + video_mode->interlaced = true; + video_mode->pixclock = SDTV_PIXCLOCK; + break; + case 480: + /* set including SAV/EAV */ + video_mode->hbp = NTSC_HBP; + video_mode->hfp = NTSC_HFP; + video_mode->vbp = NTSC_VBP_FIELD_1 + NTSC_VBP_FIELD_2; + video_mode->vfp = NTSC_VFP_FIELD_1 + NTSC_VFP_FIELD_2; + video_mode->interlaced = true; + video_mode->pixclock = SDTV_PIXCLOCK; + break; + case 486: + /* set including SAV/EAV */ + video_mode->hbp = NTSC_ORG_HBP; + video_mode->hfp = NTSC_ORG_HFP; + video_mode->vbp = NTSC_ORG_VBP_FIELD_1 + NTSC_ORG_VBP_FIELD_2; + video_mode->vfp = NTSC_ORG_VFP_FIELD_1 + NTSC_ORG_VFP_FIELD_2; + video_mode->interlaced = true; + video_mode->pixclock = SDTV_PIXCLOCK; + break; + default: + dev_warn(&ddev->dev, + "%s:Failed to find video mode x=%d, y=%d\n", + __func__, video_mode->xres, video_mode->yres); + return -EINVAL; + } + + print_vmode(video_mode); + + return 0; + +} + +static int set_video_mode( + struct mcde_display_device *ddev, struct mcde_video_mode *video_mode) +{ + int res; + struct ab8500_display_platform_data *pdata = ddev->dev.platform_data; + struct display_driver_data *driver_data = + (struct display_driver_data *)dev_get_drvdata(&ddev->dev); + AB8500_DISP_TRACE; + + if (ddev == NULL || video_mode == NULL) { + dev_warn(&ddev->dev, "%s:ddev = NULL or video_mode = NULL\n", + __func__); + return -EINVAL; + } + ddev->video_mode = *video_mode; + + if (video_mode->xres != 720) { + dev_warn(&ddev->dev, "%s:Failed to set video mode x=%d, y=%d\n", + __func__, video_mode->xres, video_mode->yres); + return -EINVAL; + } + + /* check for PAL BDGHI and N */ + switch (video_mode->yres) { + case 576: + driver_data->denc_conf.TV_std = TV_STD_PAL_BDGHI; + /* TODO: how to choose LOW DEF FILTER */ + driver_data->denc_conf.cr_filter = TV_CR_PAL_HIGH_DEF_FILTER; + /* TODO: PAL N (e.g. uses a setup of 7.5 IRE) */ + driver_data->denc_conf.black_level_setup = false; + break; + case 480: /* NTSC, PAL M DV variant */ + case 486: /* NTSC, PAL M original */ + /* TODO: PAL M */ + driver_data->denc_conf.TV_std = TV_STD_NTSC_M; + /* TODO: how to choose LOW DEF FILTER */ + driver_data->denc_conf.cr_filter = TV_CR_NTSC_HIGH_DEF_FILTER; + driver_data->denc_conf.black_level_setup = true; + break; + default: + dev_warn(&ddev->dev, "%s:Failed to set video mode x=%d, y=%d\n", + __func__, video_mode->xres, video_mode->yres); + return -EINVAL; + } + + + driver_data->denc_conf.progressive = !video_mode->interlaced; + driver_data->denc_conf.act_output = true; + driver_data->denc_conf.test_pattern = false; + driver_data->denc_conf.partial_blanking = true; + driver_data->denc_conf.blank_all = false; + driver_data->denc_conf.suppress_col = false; + driver_data->denc_conf.phase_reset_mode = TV_PHASE_RST_MOD_DISABLE; + driver_data->denc_conf.dac_enable = false; + driver_data->denc_conf.act_dc_output = true; + + set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY); + if (pdata->rgb_2_yCbCr_transform) + mcde_chnl_set_col_convert(ddev->chnl_state, + pdata->rgb_2_yCbCr_transform, + MCDE_CONVERT_RGB_2_YCBCR); + mcde_chnl_stop_flow(ddev->chnl_state); + res = mcde_chnl_set_video_mode(ddev->chnl_state, &ddev->video_mode); + if (res < 0) { + dev_warn(&ddev->dev, "%s:Failed to set video mode on channel\n", + __func__); + + return res; + } + ddev->update_flags |= UPDATE_FLAG_VIDEO_MODE; + + return 0; +} + +static int set_power_mode(struct mcde_display_device *ddev, + enum mcde_display_power_mode power_mode) +{ + int ret = 0; + int i; + struct display_driver_data *driver_data = dev_get_drvdata(&ddev->dev); + AB8500_DISP_TRACE; + + /* OFF -> STANDBY */ + if (ddev->power_mode == MCDE_DISPLAY_PM_OFF && + power_mode != MCDE_DISPLAY_PM_OFF) { + dev_dbg(&ddev->dev, "off -> standby\n"); + if (ddev->platform_enable) { + ret = ddev->platform_enable(ddev); + if (ret) + goto error; + } + if (driver_data->regulator) { + for (i = 0; i < driver_data->nr_regulators; i++) { + ret = regulator_enable( + driver_data->regulator[i]); + if (ret) + goto off_to_standby_failed; + dev_dbg(&ddev->dev, "regulator %d on\n", i); + } + } + ab8500_denc_power_up(driver_data->denc_dev); + ab8500_denc_reset(driver_data->denc_dev, true); + ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; + } + /* STANDBY -> ON */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && + power_mode == MCDE_DISPLAY_PM_ON) { + dev_dbg(&ddev->dev, "standby -> on\n"); + ddev->power_mode = MCDE_DISPLAY_PM_ON; + } + /* ON -> STANDBY */ + if (ddev->power_mode == MCDE_DISPLAY_PM_ON && + power_mode <= MCDE_DISPLAY_PM_STANDBY) { + dev_dbg(&ddev->dev, "on -> standby\n"); + ab8500_denc_reset(driver_data->denc_dev, false); + ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; + } + /* STANDBY -> OFF */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && + power_mode == MCDE_DISPLAY_PM_OFF) { + bool error = false; + dev_dbg(&ddev->dev, "standby -> off\n"); + if (driver_data->regulator) { + for (i = 0; i < driver_data->nr_regulators; i++) { + ret = regulator_disable( + driver_data->regulator[i]); + /* continue in case of an error */ + error |= (ret != 0); + dev_dbg(&ddev->dev, "regulator %d off\n", i); + } + } + if (ddev->platform_disable) { + ret = ddev->platform_disable(ddev); + error |= (ret != 0); + } + if (error) { + /* the latest error code is returned */ + goto error; + } + memset(&(ddev->video_mode), 0, sizeof(struct mcde_video_mode)); + ab8500_denc_power_down(driver_data->denc_dev); + ddev->power_mode = MCDE_DISPLAY_PM_OFF; + } + + return 0; + + /* In case of an error, try to leave in off-state */ +off_to_standby_failed: + for (i--; i >= 0; i--) + regulator_disable(driver_data->regulator[i]); + ddev->platform_disable(ddev); + +error: + dev_err(&ddev->dev, "Failed to set power mode"); + return ret; +} + +static int on_first_update(struct mcde_display_device *ddev) +{ + struct display_driver_data *driver_data = dev_get_drvdata(&ddev->dev); + + ab8500_denc_conf(driver_data->denc_dev, &driver_data->denc_conf); + ab8500_denc_conf_plug_detect(driver_data->denc_dev, true, false, + TV_PLUG_TIME_2S); + ab8500_denc_mask_int_plug_det(driver_data->denc_dev, false, false); + ddev->first_update = false; + return 0; +} + +static int display_update(struct mcde_display_device *ddev, bool tripple_buffer) +{ + int ret; + + if (ddev->first_update) + on_first_update(ddev); + if (ddev->power_mode != MCDE_DISPLAY_PM_ON && ddev->set_power_mode) { + ret = set_power_mode(ddev, MCDE_DISPLAY_PM_ON); + if (ret < 0) + goto error; + } + ret = mcde_chnl_update(ddev->chnl_state, &ddev->update_area, + tripple_buffer); + if (ret < 0) + goto error; +out: + return ret; +error: + dev_warn(&ddev->dev, "%s:Failed to set power mode to on\n", __func__); + goto out; +} + +/* Module init */ +static int __init mcde_display_tvout_ab8500_init(void) +{ + pr_debug("%s\n", __func__); + + return mcde_display_driver_register(&ab8500_driver); +} +late_initcall(mcde_display_tvout_ab8500_init); + +static void __exit mcde_display_tvout_ab8500_exit(void) +{ + pr_debug("%s\n", __func__); + + mcde_display_driver_unregister(&ab8500_driver); +} +module_exit(mcde_display_tvout_ab8500_exit); + +MODULE_AUTHOR("Marcel Tunnissen <marcel.tuennissen@stericsson.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ST-Ericsson MCDE TVout through AB8500 display driver"); diff --git a/drivers/video/mcde/display-av8100.c b/drivers/video/mcde/display-av8100.c new file mode 100644 index 00000000000..b5116621e16 --- /dev/null +++ b/drivers/video/mcde/display-av8100.c @@ -0,0 +1,1610 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson HDMI display driver + * + * Author: Per Persson <per-xb-persson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/slab.h> + +#include <video/mcde_fb.h> +#include <video/mcde_display.h> +#include <video/mcde_display-av8100.h> +#include <video/av8100.h> +#include <video/hdmi.h> + +#define SWITCH_HELPSTR ", 0=HDMI, 1=SDTV, 2=DVI\n" + +/* AVI Infoframe */ +#define AVI_INFOFRAME_DATA_SIZE 13 +#define AVI_INFOFRAME_TYPE 0x82 +#define AVI_INFOFRAME_VERSION 0x02 +#define AVI_INFOFRAME_DB1 0x10 /* Active Information present */ +#define AVI_INFOFRAME_DB2 0x08 /* Active Portion Aspect ratio */ + +#ifdef CONFIG_DISPLAY_AV8100_TRIPPLE_BUFFER +#define NUM_FB_BUFFERS 3 +#else +#define NUM_FB_BUFFERS 2 +#endif + +#define DSI_HS_FREQ_HZ 840320000 +#define DSI_LP_FREQ_HZ 19200000 + +struct cea_vesa_video_mode { + u32 cea; + u32 vesa_cea_nr; + struct mcde_video_mode *video_mode; +}; + +static int hdmi_try_video_mode( + struct mcde_display_device *ddev, struct mcde_video_mode *video_mode); +static int hdmi_set_video_mode( + struct mcde_display_device *ddev, struct mcde_video_mode *video_mode); +static int hdmi_set_pixel_format( + struct mcde_display_device *ddev, enum mcde_ovly_pix_fmt format); +static struct mcde_video_mode *video_mode_get(struct mcde_display_device *ddev, + u8 cea, u8 vesa_cea_nr); +static int ceanr_convert(struct mcde_display_device *ddev, + u8 cea, u8 vesa_cea_nr, u16 *w, u16 *h); + +static ssize_t show_hdmisdtvswitch(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t store_hdmisdtvswitch(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t show_input_pixel_format(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t store_input_pixel_format(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t show_disponoff(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t store_disponoff(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t show_vesacea(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t show_timing(struct device *dev, + struct device_attribute *attr, char *buf); +static ssize_t store_timing(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static ssize_t store_stayalive(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count); +static DEVICE_ATTR(disponoff, S_IRUGO | S_IWUSR, show_disponoff, + store_disponoff); +static DEVICE_ATTR(vesacea, S_IRUGO, show_vesacea, NULL); +static DEVICE_ATTR(timing, S_IRUGO | S_IWUSR, show_timing, store_timing); +static DEVICE_ATTR(stayalive, S_IWUSR, NULL, store_stayalive); + +static DEVICE_ATTR(hdmisdtvswitch, S_IRUGO | S_IWUSR, show_hdmisdtvswitch, + store_hdmisdtvswitch); +static DEVICE_ATTR(input_pixel_format, S_IRUGO | S_IWUSR, + show_input_pixel_format, store_input_pixel_format); + +static ssize_t show_hdmisdtvswitch(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mcde_display_device *mdev = to_mcde_display_device(dev); + int index; + + dev_dbg(dev, "%s\n", __func__); + + sprintf(buf, "%1x%s", mdev->port->hdmi_sdtv_switch, SWITCH_HELPSTR); + index = 1 + strlen(SWITCH_HELPSTR) + 1; + + return index; +} + +static ssize_t store_hdmisdtvswitch(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mcde_display_device *mdev = to_mcde_display_device(dev); + dev_dbg(dev, "%s\n", __func__); + + if (count > 0) { + if ((*buf == 0) || (*buf == '0')) { + dev_dbg(dev, "hdmi/sdtv switch = hdmi\n"); + mdev->port->hdmi_sdtv_switch = HDMI_SWITCH; + mdev->native_x_res = NATIVE_XRES_HDMI; + mdev->native_y_res = NATIVE_YRES_HDMI; + } else if ((*buf == 1) || (*buf == '1')) { + dev_dbg(dev, "hdmi/sdtv switch = sdtv\n"); + mdev->port->hdmi_sdtv_switch = SDTV_SWITCH; + mdev->native_x_res = NATIVE_XRES_SDTV; + mdev->native_y_res = NATIVE_YRES_SDTV; + } else if ((*buf == 2) || (*buf == '2')) { + dev_dbg(dev, "hdmi/sdtv switch = dvi\n"); + mdev->port->hdmi_sdtv_switch = DVI_SWITCH; + mdev->native_x_res = NATIVE_XRES_HDMI; + mdev->native_y_res = NATIVE_YRES_HDMI; + } + /* implicitely read by a memcmp in dss */ + mdev->video_mode.force_update = true; + } + + return count; +} + +static ssize_t show_input_pixel_format(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mcde_display_device *ddev = to_mcde_display_device(dev); + + return sprintf(buf, "%d\n", ddev->port->pixel_format); +} + +static ssize_t store_input_pixel_format(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mcde_display_device *ddev = to_mcde_display_device(dev); + struct display_driver_data *driver_data = dev_get_drvdata(&ddev->dev); + + dev_dbg(dev, "%s\n", __func__); + if (count > 0) { + unsigned long input; + if (strict_strtoul(buf, 10, &input) != 0) + return -EINVAL; + switch (input) { + /* intentional fall through */ + case MCDE_PORTPIXFMT_DSI_16BPP: + case MCDE_PORTPIXFMT_DSI_18BPP: + case MCDE_PORTPIXFMT_DSI_18BPP_PACKED: + case MCDE_PORTPIXFMT_DSI_24BPP: + case MCDE_PORTPIXFMT_DSI_YCBCR422: + ddev->port->pixel_format = input; + break; + default: + dev_warn(&ddev->dev, "invalid format (%ld)\n", + input); + return -EINVAL; + break; + } + /* implicitely read by a memcmp in dss */ + ddev->video_mode.force_update = true; + driver_data->update_port_pixel_format = true; + } + + return count; +} + +static ssize_t show_disponoff(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mcde_display_device *ddev = to_mcde_display_device(dev); + struct display_driver_data *driver_data = dev_get_drvdata(&ddev->dev); + + dev_dbg(dev, "%s\n", __func__); + + if (ddev->fbi && driver_data->fbdevname) { + dev_dbg(dev, "name:%s\n", driver_data->fbdevname); + strcpy(buf, driver_data->fbdevname); + return strlen(driver_data->fbdevname) + 1; + } + return 0; +} + +static ssize_t store_disponoff(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mcde_display_device *mdev = to_mcde_display_device(dev); + bool enable = false; + u8 cea = 0; + u8 vesa_cea_nr = 0; + + dev_dbg(dev, "%s\n", __func__); + + if ((count != DISPONOFF_SIZE) && (count != DISPONOFF_SIZE + 1)) + return -EINVAL; + + if ((*buf == '0') && (*(buf + 1) == '1')) + enable = true; + cea = (hex_to_bin(buf[2]) << 4) + hex_to_bin(buf[3]); + vesa_cea_nr = (hex_to_bin(buf[4]) << 4) + hex_to_bin(buf[5]); + dev_dbg(dev, "enable:%d cea:%d nr:%d\n", enable, cea, vesa_cea_nr); + + if (enable && !mdev->enabled && mdev->fbi == NULL) { + struct display_driver_data *driver_data = dev_get_drvdata(dev); + u16 w = mdev->native_x_res; + u16 h = mdev->native_y_res, vh; + int buffering = NUM_FB_BUFFERS; + struct fb_info *fbi; + + ceanr_convert(mdev, cea, vesa_cea_nr, &w, &h); + vh = h * buffering; + fbi = mcde_fb_create(mdev, w, h, w, vh, + mdev->default_pixel_format, FB_ROTATE_UR); + if (IS_ERR(fbi)) + dev_warn(dev, "fb create failed\n"); + else + driver_data->fbdevname = dev_name(fbi->dev); + } else if (!enable && mdev->enabled) { + mcde_fb_destroy(mdev); + } + + return count; +} + +static ssize_t show_timing(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mcde_display_device *ddev = to_mcde_display_device(dev); + struct display_driver_data *driver_data = dev_get_drvdata(&ddev->dev); + struct mcde_video_mode *video_mode; + int index; + + dev_dbg(dev, "%s\n", __func__); + + index = 0; + if (driver_data->video_mode) { + video_mode = driver_data->video_mode; + memcpy(buf + index, &video_mode->xres, sizeof(u32)); + index += sizeof(u32); + memcpy(buf + index, &video_mode->yres, sizeof(u32)); + index += sizeof(u32); + memcpy(buf + index, &video_mode->pixclock, sizeof(u32)); + index += sizeof(u32); + memcpy(buf + index, &video_mode->hbp, sizeof(u32)); + index += sizeof(u32); + memcpy(buf + index, &video_mode->hfp, sizeof(u32)); + index += sizeof(u32); + memcpy(buf + index, &video_mode->vbp, sizeof(u32)); + index += sizeof(u32); + memcpy(buf + index, &video_mode->vfp, sizeof(u32)); + index += sizeof(u32); + memcpy(buf + index, &video_mode->interlaced, sizeof(u32)); + index += sizeof(u32); + } + return index; +} + +static ssize_t store_timing(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mcde_display_device *ddev = to_mcde_display_device(dev); + struct display_driver_data *driver_data = dev_get_drvdata(&ddev->dev); + + dev_dbg(dev, "%s\n", __func__); + + if (count != TIMING_SIZE) + return -EINVAL; + + driver_data->video_mode = video_mode_get(ddev, *buf, *(buf + 1)); + + return count; +} + +static ssize_t store_stayalive(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mcde_display_device *ddev = to_mcde_display_device(dev); + + if (count != STAYALIVE_SIZE) + return -EINVAL; + + if ((*buf == 1) || (*buf == '1')) + ddev->stay_alive = true; + else + ddev->stay_alive = false; + + dev_dbg(dev, "%s %d\n", __func__, ddev->stay_alive); + + return count; +} + +static int ceanr_convert(struct mcde_display_device *ddev, + u8 cea, u8 vesa_cea_nr, u16 *w, u16 *h) +{ + struct mcde_video_mode *video_mode; + + dev_dbg(&ddev->dev, "%s\n", __func__); + video_mode = video_mode_get(ddev, cea, vesa_cea_nr); + if (video_mode) { + *w = video_mode->xres; + *h = video_mode->yres; + dev_dbg(&ddev->dev, "cea:%d nr:%d found\n", + cea, vesa_cea_nr); + return 0; + } + + return -EINVAL; +} + +/* Supported HDMI modes */ +static struct mcde_video_mode video_modes_supp_hdmi[] = { + /* 0 CEA #1 640_480_60_P */ + { + .xres = 640, .yres = 480, + .pixclock = 39682, + .hbp = 112, .hfp = 48, + .vbp = 33, .vfp = 12 + }, + /* 1 720_480_60_P */ + { + .xres = 720, .yres = 480, + .pixclock = 37000, + .hbp = 104, .hfp = 34, + .vbp = 30, .vfp = 15 + }, + /* 2 720_576_50_P */ + { + .xres = 720, .yres = 576, + .pixclock = 37037, + .hbp = 132, .hfp = 12, + .vbp = 44, .vfp = 5 + }, + /* 3 1280_720_60_P */ + { + .xres = 1280, .yres = 720, + .pixclock = 13468, + .hbp = 256, .hfp = 114, + .vbp = 20, .vfp = 10 + }, + /* 4 1280_720_50_P */ + { + .xres = 1280, .yres = 720, + .pixclock = 13468, + .hbp = 260, .hfp = 440, + .vbp = 25, .vfp = 5 + }, + /* 5 1280_720_30_P */ + { + .xres = 1280, .yres = 720, + .pixclock = 13468, + .hbp = 260, .hfp = 1760, + .vbp = 20, .vfp = 10 + }, + /* 6 1280_720_24_P */ + { + .xres = 1280, .yres = 720, + .pixclock = 16835, + .hbp = 260, .hfp = 1760, + .vbp = 20, .vfp = 10 + }, + /* 7 1280_720_25_P */ + { + .xres = 1280, .yres = 720, + .pixclock = 13468, + .hbp = 260, .hfp = 2420, + .vbp = 20, .vfp = 10 + }, + /* 8 1920_1080_30_P */ + { + .xres = 1920, .yres = 1080, + .pixclock = 13468, + .hbp = 189, .hfp = 91, + .vbp = 36, .vfp = 9 + }, + /* 9 1920_1080_24_P */ + { + .xres = 1920, .yres = 1080, + .pixclock = 13468, + .hbp = 170, .hfp = 660, + .vbp = 36, .vfp = 9 + }, + /* 10 1920_1080_25_P */ + { + .xres = 1920, .yres = 1080, + .pixclock = 13468, + .hbp = 192, .hfp = 528, + .vbp = 36, .vfp = 9 + }, + /* 11 720_480_60_I */ + { + .xres = 720, .yres = 480, + .pixclock = 74074, + .hbp = 126, .hfp = 12, + .vbp = 44, .vfp = 1, + .interlaced = true, + }, + /* 12 720_576_50_I */ + { + .xres = 720, .yres = 576, + .pixclock = 74074, + .hbp = 132, .hfp = 12, + .vbp = 44, .vfp = 5, + .interlaced = true, + }, + /* 13 1920_1080_50_I */ + { + .xres = 1920, .yres = 1080, + .pixclock = 13468, + .hbp = 192, .hfp = 528, + .vbp = 20, .vfp = 25, + .interlaced = true, + }, + /* 14 1920_1080_60_I */ + { + .xres = 1920, .yres = 1080, + .pixclock = 13468, + .hbp = 192, .hfp = 88, + .vbp = 20, .vfp = 25, + .interlaced = true, + }, + /* 15 VESA #9 800_600_60_P */ + { + .xres = 800, .yres = 600, + .pixclock = 25000, + .hbp = 168, .hfp = 88, + .vbp = 23, .vfp = 5, + .interlaced = false, + }, + /* 16 VESA #14 848_480_60_P */ + { + .xres = 848, .yres = 480, + .pixclock = 29630, + .hbp = 128, .hfp = 112, + .vbp = 23, .vfp = 14, + .interlaced = false, + }, + /* 17 VESA #16 1024_768_60_P */ + { + .xres = 1024, .yres = 768, + .pixclock = 15385, + .hbp = 160, .hfp = 160, + .vbp = 29, .vfp = 9, + .interlaced = false, + }, + /* 18 VESA #22 1280_768_60_P */ + { + .xres = 1280, .yres = 768, + .pixclock = 14652, + .hbp = 80, .hfp = 80, + .vbp = 12, .vfp = 10, + .interlaced = false, + }, + /* 19 VESA #23 1280_768_60_P */ + { + .xres = 1280, .yres = 768, + .pixclock = 12579, + .hbp = 192, .hfp = 192, + .vbp = 20, .vfp = 10, + .interlaced = false, + }, + /* 20 VESA #27 1280_800_60_P */ + { + .xres = 1280, .yres = 800, + .pixclock = 14085, + .hbp = 80, .hfp = 80, + .vbp = 14, .vfp = 9, + .interlaced = false, + }, + /* 21 VESA #28 1280_800_60_P */ + { + .xres = 1280, .yres = 800, + .pixclock = 11976, + .hbp = 200, .hfp = 200, + .vbp = 22, .vfp = 9, + .interlaced = false, + }, + /* 22 VESA #39 1360_768_60_P */ + { + .xres = 1360, .yres = 768, + .pixclock = 11696, + .hbp = 176, .hfp = 256, + .vbp = 18, .vfp = 9, + .interlaced = false, + }, + /* 23 VESA #81 1366_768_60_P */ + { + .xres = 1366, .yres = 768, + .pixclock = 11662, + .hbp = 213, .hfp = 213, + .vbp = 24, .vfp = 6, + .interlaced = false, + }, +}; + +/* Supported TVout modes */ +static struct mcde_video_mode video_modes_supp_sdtv[] = { + /* 720_480_60_I) */ + { + .xres = 720, .yres = 480, + .pixclock = 74074, + .hbp = 126, .hfp = 12, + .vbp = 44, .vfp = 1, + .interlaced = true, + }, + /* 720_576_50_I) */ + { + .xres = 720, .yres = 576, + .pixclock = 74074, + .hbp = 132, .hfp = 12, + .vbp = 44, .vfp = 5, + .interlaced = true, + }, +}; + +static struct cea_vesa_video_mode cea_vesa_video_mode[] = { + /* 640_480_60_P */ + { + .cea = 1, .vesa_cea_nr = 1, + .video_mode = &video_modes_supp_hdmi[0], + }, + /* 720_480_60_P */ + { + .cea = 1, .vesa_cea_nr = 2, + .video_mode = &video_modes_supp_hdmi[1], + }, + /* 720_480_60_P */ + { + .cea = 1, .vesa_cea_nr = 3, + .video_mode = &video_modes_supp_hdmi[1], + }, + /* 720_576_50_P */ + { + .cea = 1, .vesa_cea_nr = 17, + .video_mode = &video_modes_supp_hdmi[2], + }, + /* 720_576_50_P */ + { + .cea = 1, .vesa_cea_nr = 18, + .video_mode = &video_modes_supp_hdmi[2], + }, + /* 1280_720_60_P */ + { + .cea = 1, .vesa_cea_nr = 4, + .video_mode = &video_modes_supp_hdmi[3], + }, + /* 1280_720_50_P */ + { + .cea = 1, .vesa_cea_nr = 19, + .video_mode = &video_modes_supp_hdmi[4], + }, + /* 1280_720_30_P */ + { + .cea = 1, .vesa_cea_nr = 62, + .video_mode = &video_modes_supp_hdmi[5], + }, + /* 1280_720_24_P */ + { + .cea = 1, .vesa_cea_nr = 60, + .video_mode = &video_modes_supp_hdmi[6], + }, + /* 1280_720_25_P */ + { + .cea = 1, .vesa_cea_nr = 61, + .video_mode = &video_modes_supp_hdmi[7], + }, + /* 1920_1080_30_P */ + { + .cea = 1, .vesa_cea_nr = 34, + .video_mode = &video_modes_supp_hdmi[8], + }, + /* 1920_1080_24_P */ + { + .cea = 1, .vesa_cea_nr = 32, + .video_mode = &video_modes_supp_hdmi[9], + }, + /* 1920_1080_25_P */ + { + .cea = 1, .vesa_cea_nr = 33, + .video_mode = &video_modes_supp_hdmi[10], + }, + /* 720_480_60_I) */ + { + .cea = 1, .vesa_cea_nr = 6, + .video_mode = &video_modes_supp_hdmi[11], + }, + /* 720_480_60_I) */ + { + .cea = 1, .vesa_cea_nr = 7, + .video_mode = &video_modes_supp_hdmi[11], + }, + /* 720_576_50_I) */ + { + .cea = 1, .vesa_cea_nr = 21, + .video_mode = &video_modes_supp_hdmi[12], + }, + /* 720_576_50_I) */ + { + .cea = 1, .vesa_cea_nr = 22, + .video_mode = &video_modes_supp_hdmi[12], + }, + /* 1920_1080_50_I) */ + { + .cea = 1, .vesa_cea_nr = 20, + .video_mode = &video_modes_supp_hdmi[13], + }, + /* 1920_1080_60_I) */ + { + .cea = 1, .vesa_cea_nr = 5, + .video_mode = &video_modes_supp_hdmi[14], + }, + /* VESA #4 640_480_60_P) */ + { + .cea = 0, .vesa_cea_nr = 4, + .video_mode = &video_modes_supp_hdmi[0], + }, + /* VESA #9 800_600_60_P) */ + { + .cea = 0, .vesa_cea_nr = 9, + .video_mode = &video_modes_supp_hdmi[15], + }, + /* VESA #14 848_480_60_P) */ + { + .cea = 0, .vesa_cea_nr = 14, + .video_mode = &video_modes_supp_hdmi[16], + }, + /* VESA #16 1024_768_60_P) */ + { + .cea = 0, .vesa_cea_nr = 16, + .video_mode = &video_modes_supp_hdmi[17], + }, + /* VESA #22 1280_768_60_P) */ + { + .cea = 0, .vesa_cea_nr = 22, + .video_mode = &video_modes_supp_hdmi[18], + }, + /* VESA #23 1280_768_60_P) */ + { + .cea = 0, .vesa_cea_nr = 23, + .video_mode = &video_modes_supp_hdmi[19], + }, + /* VESA #27 1280_800_60_P) */ + { + .cea = 0, .vesa_cea_nr = 27, + .video_mode = &video_modes_supp_hdmi[20], + }, + /* VESA #28 1280_800_60_P) */ + { + .cea = 0, .vesa_cea_nr = 28, + .video_mode = &video_modes_supp_hdmi[21], + }, + /* VESA #39 1360_768_60_P) */ + { + .cea = 0, .vesa_cea_nr = 39, + .video_mode = &video_modes_supp_hdmi[22], + }, + /* VESA #81 1366_768_60_P) */ + { + .cea = 0, .vesa_cea_nr = 81, + .video_mode = &video_modes_supp_hdmi[23], + }, +}; + +static ssize_t show_vesacea(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int findex; + + dev_dbg(dev, "%s\n", __func__); + + for (findex = 0; findex < ARRAY_SIZE(cea_vesa_video_mode); findex++) { + *(buf + findex * 2) = cea_vesa_video_mode[findex].cea; + *(buf + findex * 2 + 1) = + cea_vesa_video_mode[findex].vesa_cea_nr; + } + *(buf + findex * 2) = '\0'; + + return findex * 2 + 1; +} + +static struct mcde_video_mode *video_mode_get(struct mcde_display_device *ddev, + u8 cea, u8 vesa_cea_nr) +{ + int findex; + + dev_dbg(&ddev->dev, "%s\n", __func__); + + for (findex = 0; findex < ARRAY_SIZE(cea_vesa_video_mode); findex++) + if ((cea == cea_vesa_video_mode[findex].cea) && + (vesa_cea_nr == + cea_vesa_video_mode[findex].vesa_cea_nr)) { + dev_dbg(&ddev->dev, "cea:%d nr:%d\n", cea, vesa_cea_nr); + return cea_vesa_video_mode[findex].video_mode; + } + + return NULL; +} + +static u8 ceanr_get(struct mcde_display_device *ddev) +{ + int cnt; + int cea; + int vesa_cea_nr; + struct mcde_video_mode *vmode = &ddev->video_mode; + struct mcde_video_mode *vmode_try; + + if (!vmode) + return 0; + + dev_dbg(&ddev->dev, "%s\n", __func__); + + for (cnt = 0; cnt < ARRAY_SIZE(cea_vesa_video_mode); cnt++) { + vmode_try = cea_vesa_video_mode[cnt].video_mode; + cea = cea_vesa_video_mode[cnt].cea; + vesa_cea_nr = cea_vesa_video_mode[cnt].vesa_cea_nr; + + if (cea && vmode_try->xres == vmode->xres && + vmode_try->yres == vmode->yres && + vmode_try->pixclock == vmode->pixclock && + vmode_try->hbp == vmode->hbp && + vmode_try->hfp == vmode->hfp && + vmode_try->vbp == vmode->vbp && + vmode_try->vfp == vmode->vfp && + vmode_try->interlaced == vmode->interlaced) { + dev_dbg(&ddev->dev, "ceanr:%d\n", vesa_cea_nr); + return vesa_cea_nr; + } + } + + return 0; +} + +#define AV8100_MAX_LEVEL 255 + +static int hdmi_try_video_mode( + struct mcde_display_device *ddev, struct mcde_video_mode *video_mode) +{ + int index = 0; + int match_level = AV8100_MAX_LEVEL; + int found_index = -1; + struct mcde_video_mode *video_modes_supp; + int array_size; + + if (ddev == NULL || video_mode == NULL) { + pr_warning("%s:ddev = NULL or video_mode = NULL\n", __func__); + return -EINVAL; + } + + dev_vdbg(&ddev->dev, "%s\n", __func__); + + if (ddev->port->hdmi_sdtv_switch == SDTV_SWITCH) { + video_mode->interlaced = true; + video_modes_supp = video_modes_supp_sdtv; + array_size = ARRAY_SIZE(video_modes_supp_sdtv); + } else { + video_modes_supp = video_modes_supp_hdmi; + array_size = ARRAY_SIZE(video_modes_supp_hdmi); + } + + while (index < array_size) { + /* 1. Check if all parameters match */ + if ((video_mode->xres == video_modes_supp[index].xres) && + (video_mode->yres == video_modes_supp[index].yres) && + ((video_mode->xres + video_mode->hbp + + video_mode->hfp) == + (video_modes_supp[index].xres + + video_modes_supp[index].hbp + + video_modes_supp[index].hfp)) && + ((video_mode->yres + video_mode->vbp + video_mode->vfp) + == + (video_modes_supp[index].yres + + video_modes_supp[index].vbp + + video_modes_supp[index].vfp)) && + (video_mode->pixclock == + video_modes_supp[index].pixclock) && + (video_mode->interlaced == + video_modes_supp[index].interlaced)) { + match_level = 1; + found_index = index; + break; + } + + /* 2. Check if xres,yres,htot,vtot,interlaced match */ + if ((match_level > 2) && + (video_mode->xres == video_modes_supp[index].xres) && + (video_mode->yres == video_modes_supp[index].yres) && + ((video_mode->xres + video_mode->hbp + + video_mode->hfp) == + (video_modes_supp[index].xres + + video_modes_supp[index].hbp + + video_modes_supp[index].hfp)) && + ((video_mode->yres + video_mode->vbp + video_mode->vfp) + == + (video_modes_supp[index].yres + + video_modes_supp[index].vbp + + video_modes_supp[index].vfp)) && + (video_mode->interlaced == + video_modes_supp[index].interlaced)) { + match_level = 2; + found_index = index; + } + + /* 3. Check if xres,yres,pixelclock,interlaced match */ + if ((match_level > 3) && + (video_mode->xres == video_modes_supp[index].xres) && + (video_mode->yres == video_modes_supp[index].yres) && + (video_mode->interlaced == + video_modes_supp[index].interlaced) && + (video_mode->pixclock == + video_modes_supp[index].pixclock)) { + match_level = 3; + found_index = index; + } + + /* 4. Check if xres,yres,interlaced match */ + if ((match_level > 4) && + (video_mode->xres == video_modes_supp[index].xres) && + (video_mode->yres == video_modes_supp[index].yres) && + (video_mode->interlaced == + video_modes_supp[index].interlaced)) { + match_level = 4; + found_index = index; + } + + index++; + } + + if (found_index == -1) { + dev_dbg(&ddev->dev, "video_mode not accepted\n"); + dev_dbg(&ddev->dev, "xres:%d yres:%d pixclock:%d hbp:%d hfp:%d " + "vfp:%d vbp:%d intlcd:%d\n", + video_mode->xres, video_mode->yres, + video_mode->pixclock, + video_mode->hbp, video_mode->hfp, + video_mode->vfp, video_mode->vbp, + video_mode->interlaced); + return -EINVAL; + } + + memset(video_mode, 0, sizeof(struct mcde_video_mode)); + memcpy(video_mode, &video_modes_supp[found_index], + sizeof(struct mcde_video_mode)); + + dev_dbg(&ddev->dev, "%s:HDMI video_mode %d chosen. Level:%d\n", + __func__, found_index, match_level); + + return 0; +} + +static int hdmi_set_video_mode( + struct mcde_display_device *dev, struct mcde_video_mode *video_mode) +{ + int ret; + union av8100_configuration av8100_config; + struct mcde_display_hdmi_platform_data *pdata; + struct display_driver_data *driver_data; + struct av8100_status status; + + /* TODO check video_mode_params */ + if (dev == NULL || video_mode == NULL) { + pr_warning("%s:ddev = NULL or video_mode = NULL\n", __func__); + return -EINVAL; + } + + pdata = dev->dev.platform_data; + driver_data = dev_get_drvdata(&dev->dev); + + dev_dbg(&dev->dev, "%s:\n", __func__); + dev_vdbg(&dev->dev, "%s:xres:%d yres:%d hbp:%d hfp:%d vbp:%d vfp:%d " + "interlaced:%d\n", __func__, + video_mode->xres, + video_mode->yres, + video_mode->hbp, + video_mode->hfp, + video_mode->vbp, + video_mode->vfp, + video_mode->interlaced); + + if (driver_data->update_port_pixel_format) { + hdmi_set_pixel_format(dev, dev->pixel_format); + driver_data->update_port_pixel_format = false; + } + + memset(&(dev->video_mode), 0, sizeof(struct mcde_video_mode)); + memcpy(&(dev->video_mode), video_mode, sizeof(struct mcde_video_mode)); + + if (dev->port->pixel_format == MCDE_PORTPIXFMT_DSI_YCBCR422 && + pdata->rgb_2_yCbCr_transform) + mcde_chnl_set_col_convert(dev->chnl_state, + pdata->rgb_2_yCbCr_transform, + MCDE_CONVERT_RGB_2_YCBCR); + mcde_chnl_stop_flow(dev->chnl_state); + + ret = mcde_chnl_set_video_mode(dev->chnl_state, &dev->video_mode); + if (ret < 0) { + dev_warn(&dev->dev, "Failed to set video mode\n"); + return ret; + } + + status = av8100_status_get(); + if (status.av8100_state == AV8100_OPMODE_UNDEFINED) + return -EINVAL; + + if (av8100_ver_get() == AV8100_CHIPVER_1) { + if (status.av8100_state >= AV8100_OPMODE_STANDBY) { + /* Disable interrupts */ + ret = av8100_disable_interrupt(); + if (ret) { + dev_err(&dev->dev, + "%s:av8100_disable_interrupt failed\n", + __func__); + return ret; + } + + ret = av8100_powerdown(); + if (ret) { + dev_err(&dev->dev, + "av8100_powerdown failed\n"); + return ret; + } + + msleep(10); + } + } + + /* Set to powerup with interrupts disabled */ + status = av8100_status_get(); + if (status.av8100_state < AV8100_OPMODE_STANDBY) { + ret = av8100_powerup(); + if (ret) { + dev_err(&dev->dev, "av8100_powerup failed\n"); + return ret; + } + } + + if (status.av8100_state <= AV8100_OPMODE_IDLE) { + ret = av8100_download_firmware(I2C_INTERFACE); + if (ret) { + dev_err(&dev->dev, "av8100_download_firmware failed\n"); + return ret; + } + } + + if (av8100_disable_interrupt()) + return -EFAULT; + + /* + * Don't look at dev->port->hdmi_sdtv_switch; it states only which + * one should be started, not which one is currently working + */ + if (av8100_conf_get(AV8100_COMMAND_HDMI, &av8100_config)) + return -EFAULT; + if (av8100_config.hdmi_format.hdmi_mode == AV8100_HDMI_ON) { + /* Set HDMI mode to OFF */ + av8100_config.hdmi_format.hdmi_mode = AV8100_HDMI_OFF; + av8100_config.hdmi_format.dvi_format = AV8100_DVI_CTRL_CTL0; + av8100_config.hdmi_format.hdmi_format = AV8100_HDMI; + if (av8100_conf_prep(AV8100_COMMAND_HDMI, &av8100_config)) + return -EFAULT; + + if (av8100_conf_w(AV8100_COMMAND_HDMI, NULL, NULL, + I2C_INTERFACE)) + return -EFAULT; + } + if (av8100_conf_get(AV8100_COMMAND_DENC, &av8100_config)) + return -EFAULT; + if (av8100_config.denc_format.enable) { + /* Turn off DENC */ + av8100_config.denc_format.enable = 0; + if (av8100_conf_prep(AV8100_COMMAND_DENC, &av8100_config)) + return -EFAULT; + if (av8100_conf_w(AV8100_COMMAND_DENC, NULL, NULL, + I2C_INTERFACE)) + return -EFAULT; + } + + /* Get current av8100 video output format */ + ret = av8100_conf_get(AV8100_COMMAND_VIDEO_OUTPUT_FORMAT, + &av8100_config); + if (ret) { + dev_err(&dev->dev, "%s:av8100_conf_get " + "AV8100_COMMAND_VIDEO_OUTPUT_FORMAT failed\n", + __func__); + return ret; + } + + if (dev->port->hdmi_sdtv_switch == SDTV_SWITCH) + av8100_config.video_output_format.video_output_cea_vesa = + dev->video_mode.yres == NATIVE_YRES_SDTV ? + AV8100_CEA21_22_576I_PAL_50HZ : + AV8100_CEA6_7_NTSC_60HZ; + else + av8100_config.video_output_format.video_output_cea_vesa = + av8100_video_output_format_get( + dev->video_mode.xres, + dev->video_mode.yres, + dev->video_mode.xres + + dev->video_mode.hbp + dev->video_mode.hfp, + dev->video_mode.yres + + dev->video_mode.vbp + dev->video_mode.vfp, + dev->video_mode.pixclock, + dev->video_mode.interlaced); + + if (AV8100_VIDEO_OUTPUT_CEA_VESA_MAX == + av8100_config.video_output_format.video_output_cea_vesa) { + dev_err(&dev->dev, "%s:video output format not found " + "\n", __func__); + return ret; + } + + ret = av8100_conf_prep(AV8100_COMMAND_VIDEO_OUTPUT_FORMAT, + &av8100_config); + if (ret) { + dev_err(&dev->dev, "%s:av8100_conf_prep " + "AV8100_COMMAND_VIDEO_OUTPUT_FORMAT failed\n", + __func__); + return ret; + } + + /* Get current av8100 video input format */ + ret = av8100_conf_get(AV8100_COMMAND_VIDEO_INPUT_FORMAT, + &av8100_config); + if (ret) { + dev_err(&dev->dev, "%s:av8100_conf_get " + "AV8100_COMMAND_VIDEO_INPUT_FORMAT failed\n", + __func__); + return ret; + } + + /* Set correct av8100 video input pixel format */ + switch (dev->port->pixel_format) { + case MCDE_PORTPIXFMT_DSI_16BPP: + default: + av8100_config.video_input_format.input_pixel_format = + AV8100_INPUT_PIX_RGB565; + break; + case MCDE_PORTPIXFMT_DSI_18BPP: + av8100_config.video_input_format.input_pixel_format = + AV8100_INPUT_PIX_RGB666; + break; + case MCDE_PORTPIXFMT_DSI_18BPP_PACKED: + av8100_config.video_input_format.input_pixel_format = + AV8100_INPUT_PIX_RGB666P; + break; + case MCDE_PORTPIXFMT_DSI_24BPP: + av8100_config.video_input_format.input_pixel_format = + AV8100_INPUT_PIX_RGB888; + break; + case MCDE_PORTPIXFMT_DSI_YCBCR422: + av8100_config.video_input_format.input_pixel_format = + AV8100_INPUT_PIX_YCBCR422; + break; + } + + /* Set ui_x4 */ + av8100_config.video_input_format.ui_x4 = dev->port->phy.dsi.ui; + + /* Set TE_config */ + switch (dev->port->sync_src) { + case MCDE_SYNCSRC_TE0: + av8100_config.video_input_format.TE_config = AV8100_TE_IT_LINE; + break; + case MCDE_SYNCSRC_TE1: + av8100_config.video_input_format.TE_config = AV8100_TE_GPIO_IT; + break; + case MCDE_SYNCSRC_TE_POLLING: + av8100_config.video_input_format.TE_config = + AV8100_TE_DSI_LANE; /* Only on DSI, no interrupts */ + break; + case MCDE_SYNCSRC_OFF: + default: + av8100_config.video_input_format.TE_config = AV8100_TE_OFF; + break; + } + + ret = av8100_conf_prep(AV8100_COMMAND_VIDEO_INPUT_FORMAT, + &av8100_config); + if (ret) { + dev_err(&dev->dev, "%s:av8100_conf_prep " + "AV8100_COMMAND_VIDEO_INPUT_FORMAT failed\n", + __func__); + return ret; + } + + ret = av8100_conf_w(AV8100_COMMAND_VIDEO_INPUT_FORMAT, + NULL, NULL, I2C_INTERFACE); + if (ret) { + dev_err(&dev->dev, "%s:av8100_conf_w " + "AV8100_COMMAND_VIDEO_INPUT_FORMAT failed\n", + __func__); + return ret; + } + + if (dev->port->hdmi_sdtv_switch == SDTV_SWITCH) { + if (dev->port->pixel_format != MCDE_PORTPIXFMT_DSI_YCBCR422) + av8100_config.color_transform = + AV8100_COLOR_TRANSFORM_RGB_TO_DENC; + else + av8100_config.color_transform = + AV8100_COLOR_TRANSFORM_YUV_TO_DENC; + } else if (dev->port->pixel_format == MCDE_PORTPIXFMT_DSI_YCBCR422) { + av8100_config.color_transform = + AV8100_COLOR_TRANSFORM_YUV_TO_RGB; + } else { + av8100_config.color_transform = + AV8100_COLOR_TRANSFORM_INDENTITY; + } + + ret = av8100_conf_prep( + AV8100_COMMAND_COLORSPACECONVERSION, + &av8100_config); + if (ret) { + dev_err(&dev->dev, "%s:av8100_configuration_prepare " + "AV8100_COMMAND_COLORSPACECONVERSION failed\n", + __func__); + return ret; + } + + ret = av8100_conf_w( + AV8100_COMMAND_COLORSPACECONVERSION, + NULL, NULL, I2C_INTERFACE); + if (ret) { + dev_err(&dev->dev, "%s:av8100_conf_w " + "AV8100_COMMAND_COLORSPACECONVERSION failed\n", + __func__); + return ret; + } + + /* Set video output format */ + ret = av8100_conf_w(AV8100_COMMAND_VIDEO_OUTPUT_FORMAT, + NULL, NULL, I2C_INTERFACE); + if (ret) { + dev_err(&dev->dev, "av8100_conf_w failed\n"); + return ret; + } + + /* Set audio input format */ + ret = av8100_conf_w(AV8100_COMMAND_AUDIO_INPUT_FORMAT, + NULL, NULL, I2C_INTERFACE); + if (ret) { + dev_err(&dev->dev, "%s:av8100_conf_w " + "AV8100_COMMAND_AUDIO_INPUT_FORMAT failed\n", + __func__); + return ret; + } + + dev->update_flags |= UPDATE_FLAG_VIDEO_MODE; + dev->first_update = true; + + return 0; +} + +static u16 rotate_byte_left(u8 c, int nr) +{ + return (0xff & (c << nr)) | (0xff & (c >> (8 - nr))); +} + +static u16 map_yv(u8 in) +{ + return rotate_byte_left(in, 3) << 4; +} + +static u16 map_u(u8 in) +{ + return rotate_byte_left(in, 5) << 4; +} + +static int hdmi_set_pixel_format( + struct mcde_display_device *ddev, enum mcde_ovly_pix_fmt format) +{ + dev_dbg(&ddev->dev, "%s\n", __func__); + ddev->pixel_format = format; + + return 0; +} + +static int hdmi_set_port_pixel_format(struct mcde_display_device *ddev) +{ + int ret; + + dev_dbg(&ddev->dev, "%s\n", __func__); + mcde_chnl_stop_flow(ddev->chnl_state); + ret = mcde_chnl_set_pixel_format(ddev->chnl_state, + ddev->port->pixel_format); + + if (ret < 0) { + dev_warn(&ddev->dev, "%s: Failed to set pixel format = %d\n", + __func__, ddev->port->pixel_format); + return ret; + } + + if (ddev->port->pixel_format == MCDE_PORTPIXFMT_DSI_YCBCR422 && + av8100_ver_get() == 2) { + /* The V2 version has an error for unpacking YUV422 */ + struct mcde_palette_table palette = { + .map_col_ch0 = *map_yv, + .map_col_ch1 = *map_u, + .map_col_ch2 = *map_yv, + }; + ret = mcde_chnl_set_palette(ddev->chnl_state, &palette); + } else { + ret = mcde_chnl_set_palette(ddev->chnl_state, NULL); + } + + return 0; +} + +static int hdmi_apply_config(struct mcde_display_device *ddev) +{ + int ret; + + if (!ddev->update_flags) + return 0; + + ret = mcde_chnl_apply(ddev->chnl_state); + if (ret < 0) { + dev_warn(&ddev->dev, "%s:Failed to apply to channel\n", + __func__); + return ret; + } + ddev->update_flags = 0; + + return 0; +} + +static int hdmi_on_first_update(struct mcde_display_device *dev) +{ + int ret; + union av8100_configuration av8100_config; + u8 *infofr_data; + int infofr_crc; + int cnt; + + dev->first_update = false; + + /* + * Prepare HDMI configuration + * Avoid simultaneous output of DENC and HDMI/DVI. + * Only one of them should be enabled. + * Note HDMI/DVI and DENC are always turned off in set_video_mode. + */ + switch (dev->port->hdmi_sdtv_switch) { + case SDTV_SWITCH: + if (av8100_conf_get(AV8100_COMMAND_DENC, &av8100_config)) + return -EFAULT; + av8100_config.denc_format.enable = 1; + if (dev->video_mode.yres == NATIVE_YRES_SDTV) { + av8100_config.denc_format.standard_selection = + AV8100_PAL_BDGHI; + av8100_config.denc_format.cvbs_video_format = + AV8100_CVBS_625; + } else { + av8100_config.denc_format.standard_selection = + AV8100_NTSC_M; + av8100_config.denc_format.cvbs_video_format = + AV8100_CVBS_525; + } + ret = av8100_conf_prep(AV8100_COMMAND_DENC, &av8100_config); + break; + case DVI_SWITCH: + av8100_config.hdmi_format.hdmi_mode = AV8100_HDMI_ON; + av8100_config.hdmi_format.hdmi_format = AV8100_DVI; + av8100_config.hdmi_format.dvi_format = AV8100_DVI_CTRL_CTL0; + ret = av8100_conf_prep(AV8100_COMMAND_HDMI, &av8100_config); + break; + case HDMI_SWITCH: + default: + av8100_config.hdmi_format.hdmi_mode = AV8100_HDMI_ON; + av8100_config.hdmi_format.hdmi_format = AV8100_HDMI; + av8100_config.hdmi_format.dvi_format = AV8100_DVI_CTRL_CTL0; + ret = av8100_conf_prep(AV8100_COMMAND_HDMI, &av8100_config); + break; + } + + if (ret) { + dev_err(&dev->dev, "%s:av8100_conf_prep " + "AV8100_COMMAND_HDMI/DENC failed\n", __func__); + return ret; + } + + /* Enable interrupts */ + ret = av8100_enable_interrupt(); + if (ret) { + dev_err(&dev->dev, "%s:av8100_enable_interrupt failed\n", + __func__); + return ret; + } + + if (dev->port->hdmi_sdtv_switch == SDTV_SWITCH) + ret = av8100_conf_w(AV8100_COMMAND_DENC, NULL, NULL, + I2C_INTERFACE); + else + ret = av8100_conf_w(AV8100_COMMAND_HDMI, NULL, NULL, + I2C_INTERFACE); + if (ret) { + dev_err(&dev->dev, "%s:av8100_conf_w " + "AV8100_COMMAND_HDMI/DENC failed\n", __func__); + return ret; + } + + /* AVI Infoframe only if HDMI */ + if (dev->port->hdmi_sdtv_switch != HDMI_SWITCH) + goto hdmi_on_first_update_end; + + /* Create AVI Infoframe */ + av8100_config.infoframes_format.type = AVI_INFOFRAME_TYPE; + av8100_config.infoframes_format.version = AVI_INFOFRAME_VERSION; + av8100_config.infoframes_format.length = AVI_INFOFRAME_DATA_SIZE; + + /* AVI Infoframe data */ + infofr_data = &av8100_config.infoframes_format.data[0]; + memset(infofr_data, 0, AVI_INFOFRAME_DATA_SIZE); + infofr_data[0] = AVI_INFOFRAME_DB1; + infofr_data[1] = AVI_INFOFRAME_DB2; + infofr_data[3] = ceanr_get(dev); + + /* Calculate AVI Infoframe checksum */ + infofr_crc = av8100_config.infoframes_format.type + + av8100_config.infoframes_format.version + + av8100_config.infoframes_format.length; + for (cnt = 0; cnt < AVI_INFOFRAME_DATA_SIZE; cnt++) + infofr_crc += infofr_data[cnt]; + infofr_crc &= 0xFF; + av8100_config.infoframes_format.crc = 0x100 - infofr_crc; + + /* Send AVI Infoframe */ + if (av8100_conf_prep(AV8100_COMMAND_INFOFRAMES, + &av8100_config) != 0) { + dev_err(&dev->dev, "av8100_conf_prep FAIL\n"); + return -EINVAL; + } + + if (av8100_conf_w(AV8100_COMMAND_INFOFRAMES, + NULL, NULL, I2C_INTERFACE) != 0) { + dev_err(&dev->dev, "av8100_conf_w FAIL\n"); + return -EINVAL; + } + +hdmi_on_first_update_end: + return ret; +} + +static int hdmi_set_power_mode(struct mcde_display_device *ddev, + enum mcde_display_power_mode power_mode) +{ + struct display_driver_data *driver_data = dev_get_drvdata(&ddev->dev); + int ret = 0; + + /* OFF -> STANDBY */ + if (ddev->power_mode == MCDE_DISPLAY_PM_OFF && + power_mode != MCDE_DISPLAY_PM_OFF) { + if (ddev->platform_enable) { + ret = ddev->platform_enable(ddev); + if (ret) + return ret; + } + + /* + * the regulator for analog TV out is only enabled here, + * this means that one needs to switch to the OFF state + * to be able to switch from HDMI to CVBS. + */ + if (ddev->port->hdmi_sdtv_switch == SDTV_SWITCH) { + ret = regulator_enable(driver_data->cvbs_regulator); + if (ret) + return ret; + driver_data->cvbs_regulator_enabled = true; + } + ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; + + hdmi_set_port_pixel_format(ddev); + } + /* STANDBY -> ON */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && + power_mode == MCDE_DISPLAY_PM_ON) { + + ddev->power_mode = MCDE_DISPLAY_PM_ON; + goto set_power_and_exit; + } + /* ON -> STANDBY */ + else if (ddev->power_mode == MCDE_DISPLAY_PM_ON && + power_mode <= MCDE_DISPLAY_PM_STANDBY) { + ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; + } + + /* STANDBY -> OFF */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && + power_mode == MCDE_DISPLAY_PM_OFF) { + memset(&(ddev->video_mode), 0, sizeof(struct mcde_video_mode)); + ret = av8100_powerscan(); + if (ret) + dev_err(&ddev->dev, "%s:av8100_powerscan failed\n" + , __func__); + if (ddev->platform_disable) { + ret = ddev->platform_disable(ddev); + if (ret) + return ret; + } + if (driver_data->cvbs_regulator_enabled) { + ret = regulator_disable(driver_data->cvbs_regulator); + if (ret) + return ret; + driver_data->cvbs_regulator_enabled = false; + } + ddev->power_mode = MCDE_DISPLAY_PM_OFF; + } + +set_power_and_exit: + mcde_chnl_set_power_mode(ddev->chnl_state, ddev->power_mode); + + return ret; +} + +static int __devinit hdmi_probe(struct mcde_display_device *dev) +{ + int ret = 0; + struct mcde_port *port; + struct display_driver_data *driver_data; + struct mcde_display_hdmi_platform_data *pdata = + dev->dev.platform_data; + + if (pdata == NULL) { + dev_err(&dev->dev, "%s:Platform data missing\n", __func__); + return -EINVAL; + } + + if (dev->port->type != MCDE_PORTTYPE_DSI) { + dev_err(&dev->dev, "%s:Invalid port type %d\n", + __func__, dev->port->type); + return -EINVAL; + } + + driver_data = (struct display_driver_data *) + kzalloc(sizeof(struct display_driver_data), GFP_KERNEL); + if (!driver_data) { + dev_err(&dev->dev, "Failed to allocate driver data\n"); + return -ENOMEM; + } + + /* DSI use clock continous mode if AV8100_CHIPVER_1 > 1 */ + if (av8100_ver_get() > AV8100_CHIPVER_1) + dev->port->phy.dsi.clk_cont = true; + + dev->on_first_update = hdmi_on_first_update; + dev->try_video_mode = hdmi_try_video_mode; + dev->set_video_mode = hdmi_set_video_mode; + dev->apply_config = hdmi_apply_config; + dev->set_pixel_format = hdmi_set_pixel_format; + dev->set_power_mode = hdmi_set_power_mode; + + port = dev->port; + + port->phy.dsi.host_eot_gen = true; + port->phy.dsi.num_data_lanes = 2; + port->phy.dsi.hs_freq = DSI_HS_FREQ_HZ; + port->phy.dsi.lp_freq = DSI_LP_FREQ_HZ; + + /* Create sysfs files */ + if (device_create_file(&dev->dev, &dev_attr_hdmisdtvswitch)) + dev_info(&dev->dev, + "Unable to create hdmisdtvswitch attr\n"); + if (device_create_file(&dev->dev, &dev_attr_input_pixel_format)) + dev_info(&dev->dev, + "Unable to create input_pixel_format attr\n"); + if (device_create_file(&dev->dev, &dev_attr_disponoff)) + dev_info(&dev->dev, + "Unable to create disponoff attr\n"); + if (device_create_file(&dev->dev, &dev_attr_vesacea)) + dev_info(&dev->dev, + "Unable to create ceavesa attr\n"); + if (device_create_file(&dev->dev, &dev_attr_timing)) + dev_info(&dev->dev, + "Unable to create timing attr\n"); + if (device_create_file(&dev->dev, &dev_attr_stayalive)) + dev_info(&dev->dev, + "Unable to create stayalive attr\n"); + + if (pdata->cvbs_regulator_id) { + driver_data->cvbs_regulator = regulator_get(&dev->dev, + pdata->cvbs_regulator_id); + if (IS_ERR(driver_data->cvbs_regulator)) { + ret = PTR_ERR(driver_data->cvbs_regulator); + dev_warn(&dev->dev, "%s:Failed to get regulator %s\n", + __func__, pdata->cvbs_regulator_id); + driver_data->cvbs_regulator = NULL; + goto av_regulator_get_failed; + } + } + + dev_set_drvdata(&dev->dev, driver_data); + dev_info(&dev->dev, "HDMI display probed\n"); + + return 0; + +av_regulator_get_failed: + kfree(driver_data); + return ret; +} + +static int __devexit hdmi_remove(struct mcde_display_device *dev) +{ + struct display_driver_data *driver_data = dev_get_drvdata(&dev->dev); + struct mcde_display_hdmi_platform_data *pdata = + dev->dev.platform_data; + + /* Remove sysfs files */ + device_remove_file(&dev->dev, &dev_attr_input_pixel_format); + device_remove_file(&dev->dev, &dev_attr_hdmisdtvswitch); + device_remove_file(&dev->dev, &dev_attr_disponoff); + device_remove_file(&dev->dev, &dev_attr_vesacea); + device_remove_file(&dev->dev, &dev_attr_timing); + device_remove_file(&dev->dev, &dev_attr_stayalive); + + dev->set_power_mode(dev, MCDE_DISPLAY_PM_OFF); + + if (driver_data->cvbs_regulator) + regulator_put(driver_data->cvbs_regulator); + kfree(driver_data); + if (pdata->hdmi_platform_enable) { + if (pdata->regulator) + regulator_put(pdata->regulator); + if (pdata->reset_gpio) { + gpio_direction_input(pdata->reset_gpio); + gpio_free(pdata->reset_gpio); + } + } + + return 0; +} + +#if !defined(CONFIG_HAS_EARLYSUSPEND) && defined(CONFIG_PM) +static int hdmi_resume(struct mcde_display_device *ddev) +{ + int ret; + + if (ddev->chnl_state == NULL) + return 0; + + /* set_power_mode will handle call platform_enable */ + ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY); + if (ret < 0) + dev_warn(&ddev->dev, "%s:Failed to resume display\n" + , __func__); + + return ret; +} + +static int hdmi_suspend(struct mcde_display_device *ddev, pm_message_t state) +{ + int ret; + + if (ddev->chnl_state == NULL) + return 0; + + /* set_power_mode will handle call platform_disable */ + ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF); + if (ret < 0) + dev_warn(&ddev->dev, "%s:Failed to suspend display\n" + , __func__); + + return ret; +} +#endif + +static struct mcde_display_driver hdmi_driver = { + .probe = hdmi_probe, + .remove = hdmi_remove, +#if !defined(CONFIG_HAS_EARLYSUSPEND) && defined(CONFIG_PM) + .suspend = hdmi_suspend, + .resume = hdmi_resume, +#else + .suspend = NULL, + .resume = NULL, +#endif + .driver = { + .name = "av8100_hdmi", + }, +}; + +/* Module init */ +static int __init mcde_display_hdmi_init(void) +{ + pr_info("%s\n", __func__); + + return mcde_display_driver_register(&hdmi_driver); + +} +late_initcall(mcde_display_hdmi_init); + +static void __exit mcde_display_hdmi_exit(void) +{ + pr_info("%s\n", __func__); + + mcde_display_driver_unregister(&hdmi_driver); +} +module_exit(mcde_display_hdmi_exit); + +MODULE_AUTHOR("Per Persson <per.xb.persson@stericsson.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ST-Ericsson hdmi display driver"); diff --git a/drivers/video/mcde/display-fictive.c b/drivers/video/mcde/display-fictive.c new file mode 100644 index 00000000000..c7ea1429b9f --- /dev/null +++ b/drivers/video/mcde/display-fictive.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * ST-Ericsson MCDE fictive display driver + * + * Author: Per Persson <per.xb.persson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/err.h> + +#include <video/mcde_display.h> + +static int __devinit fictive_probe(struct mcde_display_device *dev) +{ + dev->platform_enable = NULL, + dev->platform_disable = NULL, + dev->set_power_mode = NULL; + + dev_info(&dev->dev, "Fictive display probed\n"); + + return 0; +} + +static int __devexit fictive_remove(struct mcde_display_device *dev) +{ + return 0; +} + +static struct mcde_display_driver fictive_driver = { + .probe = fictive_probe, + .remove = fictive_remove, + .driver = { + .name = "mcde_disp_fictive", + }, +}; + +/* Module init */ +static int __init mcde_display_fictive_init(void) +{ + pr_info("%s\n", __func__); + + return mcde_display_driver_register(&fictive_driver); +} +module_init(mcde_display_fictive_init); + +static void __exit mcde_display_fictive_exit(void) +{ + pr_info("%s\n", __func__); + + mcde_display_driver_unregister(&fictive_driver); +} +module_exit(mcde_display_fictive_exit); + +MODULE_AUTHOR("Per Persson <per.xb.persson@stericsson.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ST-Ericsson MCDE fictive display driver"); diff --git a/drivers/video/mcde/display-generic_dsi.c b/drivers/video/mcde/display-generic_dsi.c new file mode 100644 index 00000000000..6c63f4cd750 --- /dev/null +++ b/drivers/video/mcde/display-generic_dsi.c @@ -0,0 +1,309 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson MCDE generic DCS display driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/err.h> + +#include <video/mcde_display.h> +#include <video/mcde_display-generic_dsi.h> + +static int generic_platform_enable(struct mcde_display_device *dev) +{ + struct mcde_display_generic_platform_data *pdata = + dev->dev.platform_data; + + dev_dbg(&dev->dev, "%s: Reset & power on generic display\n", __func__); + + if (pdata->regulator) { + if (regulator_enable(pdata->regulator) < 0) { + dev_err(&dev->dev, "%s:Failed to enable regulator\n" + , __func__); + return -EINVAL; + } + } + if (pdata->reset_gpio) + gpio_set_value_cansleep(pdata->reset_gpio, pdata->reset_high); + mdelay(pdata->reset_delay); + if (pdata->reset_gpio) + gpio_set_value_cansleep(pdata->reset_gpio, !pdata->reset_high); + + return 0; +} + +static int generic_platform_disable(struct mcde_display_device *dev) +{ + struct mcde_display_generic_platform_data *pdata = + dev->dev.platform_data; + + dev_dbg(&dev->dev, "%s:Reset & power off generic display\n", __func__); + + if (pdata->regulator) { + if (regulator_disable(pdata->regulator) < 0) { + dev_err(&dev->dev, "%s:Failed to disable regulator\n" + , __func__); + return -EINVAL; + } + } + return 0; +} + +static int generic_set_power_mode(struct mcde_display_device *ddev, + enum mcde_display_power_mode power_mode) +{ + int ret = 0; + struct mcde_display_generic_platform_data *pdata = + ddev->dev.platform_data; + + dev_dbg(&ddev->dev, "%s:Set Power mode\n", __func__); + + /* OFF -> STANDBY */ + if (ddev->power_mode == MCDE_DISPLAY_PM_OFF && + power_mode != MCDE_DISPLAY_PM_OFF) { + + if (ddev->platform_enable) { + ret = ddev->platform_enable(ddev); + if (ret) + return ret; + } + + ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; + } + + /* STANDBY -> ON */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && + power_mode == MCDE_DISPLAY_PM_ON) { + + ret = mcde_dsi_dcs_write(ddev->chnl_state, + DCS_CMD_EXIT_SLEEP_MODE, NULL, 0); + if (ret) + return ret; + + msleep(pdata->sleep_out_delay); + + ret = mcde_dsi_dcs_write(ddev->chnl_state, + DCS_CMD_SET_DISPLAY_ON, NULL, 0); + if (ret) + return ret; + + ddev->power_mode = MCDE_DISPLAY_PM_ON; + goto set_power_and_exit; + } + /* ON -> STANDBY */ + else if (ddev->power_mode == MCDE_DISPLAY_PM_ON && + power_mode <= MCDE_DISPLAY_PM_STANDBY) { + ret = mcde_dsi_dcs_write(ddev->chnl_state, + DCS_CMD_SET_DISPLAY_OFF, NULL, 0); + if (ret) + return ret; + + ret = mcde_dsi_dcs_write(ddev->chnl_state, + DCS_CMD_ENTER_SLEEP_MODE, NULL, 0); + if (ret) + return ret; + + ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; + } + + /* SLEEP -> OFF */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && + power_mode == MCDE_DISPLAY_PM_OFF) { + if (ddev->platform_disable) { + ret = ddev->platform_disable(ddev); + if (ret) + return ret; + } + ddev->power_mode = MCDE_DISPLAY_PM_OFF; + } + +set_power_and_exit: + mcde_chnl_set_power_mode(ddev->chnl_state, ddev->power_mode); + + return ret; +} + +static int __devinit generic_probe(struct mcde_display_device *dev) +{ + int ret = 0; + struct mcde_display_generic_platform_data *pdata = + dev->dev.platform_data; + + if (pdata == NULL) { + dev_err(&dev->dev, "%s:Platform data missing\n", __func__); + return -EINVAL; + } + + if (dev->port->type != MCDE_PORTTYPE_DSI) { + dev_err(&dev->dev, + "%s:Invalid port type %d\n", + __func__, dev->port->type); + return -EINVAL; + } + + if (!dev->platform_enable && !dev->platform_disable) { + pdata->generic_platform_enable = true; + if (pdata->reset_gpio) { + ret = gpio_request(pdata->reset_gpio, NULL); + if (ret) { + dev_warn(&dev->dev, + "%s:Failed to request gpio %d\n", + __func__, pdata->reset_gpio); + goto gpio_request_failed; + } + gpio_direction_output(pdata->reset_gpio, + !pdata->reset_high); + } + if (pdata->regulator_id) { + pdata->regulator = regulator_get(&dev->dev, + pdata->regulator_id); + if (IS_ERR(pdata->regulator)) { + ret = PTR_ERR(pdata->regulator); + dev_warn(&dev->dev, + "%s:Failed to get regulator '%s'\n", + __func__, pdata->regulator_id); + pdata->regulator = NULL; + goto regulator_get_failed; + } + + if (regulator_set_voltage(pdata->regulator, + pdata->min_supply_voltage, + pdata->max_supply_voltage) < 0) { + int volt; + + dev_warn(&dev->dev, + "%s:Failed to set voltage '%s'\n", + __func__, pdata->regulator_id); + volt = regulator_get_voltage(pdata->regulator); + dev_warn(&dev->dev, + "Voltage:%d\n", volt); + } + + /* + * When u-boot has display a startup screen. + * U-boot has turned on display power however the + * regulator framework does not know about that + * This is the case here, the display driver has to + * enable the regulator for the display. + */ + if (dev->power_mode == MCDE_DISPLAY_PM_STANDBY) { + ret = regulator_enable(pdata->regulator); + if (ret < 0) { + dev_err(&dev->dev, + "%s:Failed to enable regulator\n" + , __func__); + goto regulator_enable_failed; + } + } + } + } + + dev->platform_enable = generic_platform_enable, + dev->platform_disable = generic_platform_disable, + dev->set_power_mode = generic_set_power_mode; + + dev_info(&dev->dev, "Generic display probed\n"); + + goto out; +regulator_enable_failed: +regulator_get_failed: + if (pdata->generic_platform_enable && pdata->reset_gpio) + gpio_free(pdata->reset_gpio); +gpio_request_failed: +out: + return ret; +} + +static int __devexit generic_remove(struct mcde_display_device *dev) +{ + struct mcde_display_generic_platform_data *pdata = + dev->dev.platform_data; + + dev->set_power_mode(dev, MCDE_DISPLAY_PM_OFF); + + if (!pdata->generic_platform_enable) + return 0; + + if (pdata->regulator) + regulator_put(pdata->regulator); + if (pdata->reset_gpio) { + gpio_direction_input(pdata->reset_gpio); + gpio_free(pdata->reset_gpio); + } + + return 0; +} + +#if !defined(CONFIG_HAS_EARLYSUSPEND) && defined(CONFIG_PM) +static int generic_resume(struct mcde_display_device *ddev) +{ + int ret; + + /* set_power_mode will handle call platform_enable */ + ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY); + if (ret < 0) + dev_warn(&ddev->dev, "%s:Failed to resume display\n" + , __func__); + ddev->set_synchronized_update(ddev, + ddev->get_synchronized_update(ddev)); + return ret; +} + +static int generic_suspend(struct mcde_display_device *ddev, pm_message_t state) +{ + int ret; + + /* set_power_mode will handle call platform_disable */ + ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF); + if (ret < 0) + dev_warn(&ddev->dev, "%s:Failed to suspend display\n" + , __func__); + return ret; +} +#endif + +static struct mcde_display_driver generic_driver = { + .probe = generic_probe, + .remove = generic_remove, +#if !defined(CONFIG_HAS_EARLYSUSPEND) && defined(CONFIG_PM) + .suspend = generic_suspend, + .resume = generic_resume, +#else + .suspend = NULL, + .resume = NULL, +#endif + .driver = { + .name = "mcde_disp_generic", + }, +}; + +/* Module init */ +static int __init mcde_display_generic_init(void) +{ + pr_info("%s\n", __func__); + + return mcde_display_driver_register(&generic_driver); +} +module_init(mcde_display_generic_init); + +static void __exit mcde_display_generic_exit(void) +{ + pr_info("%s\n", __func__); + + mcde_display_driver_unregister(&generic_driver); +} +module_exit(mcde_display_generic_exit); + +MODULE_AUTHOR("Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ST-Ericsson MCDE generic DCS display driver"); diff --git a/drivers/video/mcde/display-samsung_s6d16d0.c b/drivers/video/mcde/display-samsung_s6d16d0.c new file mode 100644 index 00000000000..62db3db6556 --- /dev/null +++ b/drivers/video/mcde/display-samsung_s6d16d0.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson MCDE Samsung S6D16D0 display driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/regulator/consumer.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/err.h> + +#include <video/mcde_display.h> + +#define RESET_DURATION_US 10 +#define RESET_DELAY_MS 120 +#define SLEEP_OUT_DELAY_MS 120 +#define IO_REGU "vdd1" +#define IO_REGU_MIN 1650000 +#define IO_REGU_MAX 3300000 + +#define DSI_HS_FREQ_HZ 420160000 +#define DSI_LP_FREQ_HZ 19200000 + +struct device_info { + int reset_gpio; + struct mcde_port port; + struct regulator *regulator; +}; + +static inline struct device_info *get_drvdata(struct mcde_display_device *ddev) +{ + return (struct device_info *)dev_get_drvdata(&ddev->dev); +} + +static int power_on(struct mcde_display_device *ddev) +{ + struct device_info *di = get_drvdata(ddev); + + dev_dbg(&ddev->dev, "Reset & power on s6d16d0 display\n"); + + regulator_enable(di->regulator); + gpio_set_value_cansleep(di->reset_gpio, 0); + udelay(RESET_DURATION_US); + gpio_set_value_cansleep(di->reset_gpio, 1); + msleep(RESET_DELAY_MS); + + return 0; +} + +static int power_off(struct mcde_display_device *ddev) +{ + struct device_info *di = get_drvdata(ddev); + + dev_dbg(&ddev->dev, "Power off s6d16d0 display\n"); + + regulator_disable(di->regulator); + + return 0; +} + +static int display_on(struct mcde_display_device *ddev) +{ + int ret; + + dev_dbg(&ddev->dev, "Display on s6d16d0\n"); + + ret = mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_EXIT_SLEEP_MODE, + NULL, 0); + if (ret) + return ret; + msleep(SLEEP_OUT_DELAY_MS); + return mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_SET_DISPLAY_ON, + NULL, 0); +} + +static int display_off(struct mcde_display_device *ddev) +{ + int ret; + + dev_dbg(&ddev->dev, "Display off s6d16d0\n"); + + ret = mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_SET_DISPLAY_OFF, + NULL, 0); + if (ret) + return ret; + + return mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_ENTER_SLEEP_MODE, + NULL, 0); +} + +static int set_power_mode(struct mcde_display_device *ddev, + enum mcde_display_power_mode power_mode) +{ + int ret = 0; + + dev_dbg(&ddev->dev, "Set power mode %d\n", power_mode); + + /* OFF -> STANDBY */ + if (ddev->power_mode == MCDE_DISPLAY_PM_OFF && + power_mode != MCDE_DISPLAY_PM_OFF) { + ret = power_on(ddev); + if (ret) + return ret; + ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; + } + + /* STANDBY -> ON */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && + power_mode == MCDE_DISPLAY_PM_ON) { + + ret = display_on(ddev); + if (ret) + return ret; + ddev->power_mode = MCDE_DISPLAY_PM_ON; + } + /* ON -> STANDBY */ + else if (ddev->power_mode == MCDE_DISPLAY_PM_ON && + power_mode <= MCDE_DISPLAY_PM_STANDBY) { + + ret = display_off(ddev); + if (ret) + return ret; + ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; + } + + /* STANDBY -> OFF */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && + power_mode == MCDE_DISPLAY_PM_OFF) { + ret = power_off(ddev); + if (ret) + return ret; + ddev->power_mode = MCDE_DISPLAY_PM_OFF; + } + + return mcde_chnl_set_power_mode(ddev->chnl_state, ddev->power_mode); +} + +static int __devinit samsung_s6d16d0_probe(struct mcde_display_device *ddev) +{ + int ret = 0; + struct mcde_display_dsi_platform_data *pdata = ddev->dev.platform_data; + struct device_info *di; + + if (pdata == NULL || !pdata->reset_gpio) { + dev_err(&ddev->dev, "Invalid platform data\n"); + return -EINVAL; + } + + di = kzalloc(sizeof(*di), GFP_KERNEL); + if (!di) + return -ENOMEM; + di->reset_gpio = pdata->reset_gpio; + di->port.link = pdata->link; + di->port.type = MCDE_PORTTYPE_DSI; + di->port.mode = MCDE_PORTMODE_CMD; + di->port.pixel_format = MCDE_PORTPIXFMT_DSI_24BPP; + di->port.sync_src = MCDE_SYNCSRC_BTA; + di->port.phy.dsi.num_data_lanes = 2; + di->port.phy.dsi.host_eot_gen = true; + /* TODO: Move UI to mcde_hw.c when clk_get_rate(dsi) is done */ + di->port.phy.dsi.ui = 9; + di->port.phy.dsi.hs_freq = DSI_HS_FREQ_HZ; + di->port.phy.dsi.lp_freq = DSI_LP_FREQ_HZ; + + ret = gpio_request(di->reset_gpio, NULL); + if (ret) + goto gpio_request_failed; + gpio_direction_output(di->reset_gpio, 1); + di->regulator = regulator_get(&ddev->dev, IO_REGU); + if (IS_ERR(di->regulator)) { + di->regulator = NULL; + goto regulator_get_failed; + } + ret = regulator_set_voltage(di->regulator, IO_REGU_MIN, IO_REGU_MAX); + if (WARN_ON(ret)) + goto regulator_voltage_failed; + + /* Get in sync with u-boot */ + if (ddev->power_mode != MCDE_DISPLAY_PM_OFF) + (void)regulator_enable(di->regulator); + + ddev->set_power_mode = set_power_mode; + ddev->port = &di->port; + ddev->native_x_res = 864; + ddev->native_y_res = 480; + dev_set_drvdata(&ddev->dev, di); + + dev_info(&ddev->dev, "Samsung s6d16d0 display probed\n"); + + return 0; +regulator_voltage_failed: + regulator_put(di->regulator); +regulator_get_failed: + gpio_free(di->reset_gpio); +gpio_request_failed: + kfree(di); + return ret; +} + +static struct mcde_display_driver samsung_s6d16d0_driver = { + .probe = samsung_s6d16d0_probe, + .driver = { + .name = "samsung_s6d16d0", + }, +}; + +static int __init samsung_s6d16d0_init(void) +{ + return mcde_display_driver_register(&samsung_s6d16d0_driver); +} +module_init(samsung_s6d16d0_init); + +MODULE_AUTHOR("Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ST-Ericsson MCDE Samsung S6D16D0 display driver"); diff --git a/drivers/video/mcde/display-sony_acx424akp_dsi.c b/drivers/video/mcde/display-sony_acx424akp_dsi.c new file mode 100644 index 00000000000..44302de8f1b --- /dev/null +++ b/drivers/video/mcde/display-sony_acx424akp_dsi.c @@ -0,0 +1,412 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson MCDE Sony acx424akp DCS display driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/err.h> +#include <linux/slab.h> + +#include <linux/regulator/consumer.h> + +#include <video/mcde_display.h> +#include <video/mcde_display-sony_acx424akp_dsi.h> + +#define RESET_DELAY_MS 11 +#define RESET_LOW_DELAY_US 20 +#define SLEEP_OUT_DELAY_MS 140 +#define IO_REGU "vddi" +#define IO_REGU_MIN 1600000 +#define IO_REGU_MAX 3300000 + +#define DSI_HS_FREQ_HZ 420160000 +#define DSI_LP_FREQ_HZ 19200000 + +struct device_info { + int reset_gpio; + struct mcde_port port; + struct regulator *regulator; +}; + +static inline struct device_info *get_drvdata(struct mcde_display_device *ddev) +{ + return (struct device_info *)dev_get_drvdata(&ddev->dev); +} + +static int display_read_deviceid(struct mcde_display_device *dev, u16 *id) +{ + struct mcde_chnl_state *chnl; + + u8 id1, id2, id3; + int len = 1; + int ret = 0; + int readret = 0; + + dev_dbg(&dev->dev, "%s: Read device id of the display\n", __func__); + + /* Acquire MCDE resources */ + chnl = mcde_chnl_get(dev->chnl_id, dev->fifo, dev->port); + if (IS_ERR(chnl)) { + ret = PTR_ERR(chnl); + dev_warn(&dev->dev, "Failed to acquire MCDE channel\n"); + goto out; + } + + /* plugnplay: use registers DA, DBh and DCh to detect display */ + readret = mcde_dsi_dcs_read(chnl, 0xDA, (u32 *)&id1, &len); + if (!readret) + readret = mcde_dsi_dcs_read(chnl, 0xDB, (u32 *)&id2, &len); + if (!readret) + readret = mcde_dsi_dcs_read(chnl, 0xDC, (u32 *)&id3, &len); + + if (readret) { + dev_info(&dev->dev, + "mcde_dsi_dcs_read failed to read display ID\n"); + goto read_fail; + } + + *id = (id3 << 8) | id2; +read_fail: + /* close MCDE channel */ + mcde_chnl_put(chnl); +out: + return 0; +} + +static int power_on(struct mcde_display_device *dev) +{ + struct device_info *di = get_drvdata(dev); + + dev_dbg(&dev->dev, "%s: Reset & power on sony display\n", __func__); + + regulator_enable(di->regulator); + gpio_set_value_cansleep(di->reset_gpio, 1); + msleep(RESET_DELAY_MS); + gpio_set_value_cansleep(di->reset_gpio, 0); + udelay(RESET_LOW_DELAY_US); + gpio_set_value_cansleep(di->reset_gpio, 1); + msleep(RESET_DELAY_MS); + + return 0; +} + +static int power_off(struct mcde_display_device *dev) +{ + struct device_info *di = get_drvdata(dev); + + dev_dbg(&dev->dev, "%s:Reset & power off sony display\n", __func__); + + gpio_set_value_cansleep(di->reset_gpio, 0); + msleep(RESET_DELAY_MS); + regulator_disable(di->regulator); + + return 0; +} + +static int display_on(struct mcde_display_device *ddev) +{ + int ret; + + dev_dbg(&ddev->dev, "Display on sony display\n"); + + ret = mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_EXIT_SLEEP_MODE, + NULL, 0); + if (ret) + return ret; + msleep(SLEEP_OUT_DELAY_MS); + return mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_SET_DISPLAY_ON, + NULL, 0); +} + +static int display_off(struct mcde_display_device *ddev) +{ + int ret; + + dev_dbg(&ddev->dev, "Display off sony display\n"); + + ret = mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_SET_DISPLAY_OFF, + NULL, 0); + if (ret) + return ret; + + return mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_ENTER_SLEEP_MODE, + NULL, 0); +} + +static int sony_acx424akp_set_scan_mode(struct mcde_display_device *ddev, + enum mcde_display_power_mode power_mode) +{ + int ret = 0; + u8 param[MCDE_MAX_DSI_DIRECT_CMD_WRITE]; + + dev_dbg(&ddev->dev, "%s:Set Power mode\n", __func__); + + /* 180 rotation for SONY ACX424AKP display */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY) { + param[0] = 0xAA; + ret = mcde_dsi_dcs_write(ddev->chnl_state, 0xf3, param, 1); + if (ret) + return ret; + + param[0] = 0x00; + param[1] = 0x00; + ret = mcde_dsi_generic_write(ddev->chnl_state, param, 3); + if (ret) + return ret; + + param[0] = 0xC9; + param[1] = 0x01; + ret = mcde_dsi_generic_write(ddev->chnl_state, param, 3); + if (ret) + return ret; + + param[0] = 0xA2; + param[1] = 0x00; + ret = mcde_dsi_generic_write(ddev->chnl_state, param, 3); + if (ret) + return ret; + + param[0] = 0xFF; + param[1] = 0xAA; + ret = mcde_dsi_generic_write(ddev->chnl_state, param, 3); + if (ret) + return ret; + } + return ret; +} + +static int sony_acx424akp_set_power_mode(struct mcde_display_device *ddev, + enum mcde_display_power_mode power_mode) +{ + int ret = 0; + + dev_dbg(&ddev->dev, "%s:Set Power mode\n", __func__); + + /* OFF -> STANDBY */ + if (ddev->power_mode == MCDE_DISPLAY_PM_OFF && + power_mode != MCDE_DISPLAY_PM_OFF) { + ret = power_on(ddev); + if (ret) + return ret; + ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; + } + + /* STANDBY -> ON */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && + power_mode == MCDE_DISPLAY_PM_ON) { + + ret = display_on(ddev); + if (ret) + return ret; + ddev->power_mode = MCDE_DISPLAY_PM_ON; + } + /* ON -> STANDBY */ + else if (ddev->power_mode == MCDE_DISPLAY_PM_ON && + power_mode <= MCDE_DISPLAY_PM_STANDBY) { + + ret = display_off(ddev); + if (ret) + return ret; + ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; + } + + /* STANDBY -> OFF */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && + power_mode == MCDE_DISPLAY_PM_OFF) { + ret = power_off(ddev); + if (ret) + return ret; + ddev->power_mode = MCDE_DISPLAY_PM_OFF; + } + + mcde_chnl_set_power_mode(ddev->chnl_state, ddev->power_mode); + return sony_acx424akp_set_scan_mode(ddev, power_mode); +} + +static int __devinit sony_acx424akp_probe(struct mcde_display_device *dev) +{ + int ret = 0; + u16 id = 0; + struct device_info *di; + struct mcde_port *port; + struct mcde_display_sony_acx424akp_platform_data *pdata = + dev->dev.platform_data; + + if (pdata == NULL || !pdata->reset_gpio) { + dev_err(&dev->dev, "Invalid platform data\n"); + return -EINVAL; + } + + di = kzalloc(sizeof(*di), GFP_KERNEL); + if (!di) + return -ENOMEM; + + port = dev->port; + di->reset_gpio = pdata->reset_gpio; + di->port.type = MCDE_PORTTYPE_DSI; + di->port.mode = MCDE_PORTMODE_CMD; + di->port.pixel_format = MCDE_PORTPIXFMT_DSI_24BPP; + di->port.sync_src = MCDE_SYNCSRC_BTA; + di->port.phy.dsi.num_data_lanes = 2; + di->port.link = port->link; + di->port.phy.dsi.host_eot_gen = true; + /* TODO: Move UI to mcde_hw.c when clk_get_rate(dsi) is done */ + di->port.phy.dsi.ui = 9; + di->port.phy.dsi.hs_freq = DSI_HS_FREQ_HZ; + di->port.phy.dsi.lp_freq = DSI_LP_FREQ_HZ; + + ret = gpio_request(di->reset_gpio, NULL); + if (WARN_ON(ret)) + goto gpio_request_failed; + + gpio_direction_output(di->reset_gpio, 1); + di->regulator = regulator_get(&dev->dev, IO_REGU); + if (IS_ERR(di->regulator)) { + ret = PTR_ERR(di->regulator); + di->regulator = NULL; + goto regulator_get_failed; + } + ret = regulator_set_voltage(di->regulator, IO_REGU_MIN, IO_REGU_MAX); + if (WARN_ON(ret)) + goto regulator_voltage_failed; + + dev->set_power_mode = sony_acx424akp_set_power_mode; + + dev->port = &di->port; + dev->native_x_res = 480; + dev->native_y_res = 854; + dev_set_drvdata(&dev->dev, di); + + /* + * When u-boot has display a startup screen. + * U-boot has turned on display power however the + * regulator framework does not know about that + * This is the case here, the display driver has to + * enable the regulator for the display. + */ + if (dev->power_mode != MCDE_DISPLAY_PM_OFF) { + (void) regulator_enable(di->regulator); + } else { + power_on(dev); + dev->power_mode = MCDE_DISPLAY_PM_STANDBY; + } + + ret = display_read_deviceid(dev, &id); + if (ret) + goto read_id_failed; + + switch (id) { + case DISPLAY_SONY_ACX424AKP: + case DISPLAY_SONY_ACX424AKP_ID2: + pdata->disp_panel = id; + dev_info(&dev->dev, + "Sony ACX424AKP display (ID 0x%.4X) probed\n", id); + break; + default: + pdata->disp_panel = DISPLAY_NONE; + dev_info(&dev->dev, + "Display not recognized (ID 0x%.4X) probed\n", id); + goto read_id_failed; + } + + return 0; + +read_id_failed: +regulator_voltage_failed: + regulator_put(di->regulator); +regulator_get_failed: + gpio_free(di->reset_gpio); +gpio_request_failed: + kfree(di); + return ret; +} + +static int __devexit sony_acx424akp_remove(struct mcde_display_device *dev) +{ + struct device_info *di = get_drvdata(dev); + + dev->set_power_mode(dev, MCDE_DISPLAY_PM_OFF); + + regulator_put(di->regulator); + gpio_direction_input(di->reset_gpio); + gpio_free(di->reset_gpio); + + kfree(di); + + return 0; +} + +#if !defined(CONFIG_HAS_EARLYSUSPEND) && defined(CONFIG_PM) +static int sony_acx424akp_resume(struct mcde_display_device *ddev) +{ + int ret; + + /* set_power_mode will handle call platform_enable */ + ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY); + if (ret < 0) + dev_warn(&ddev->dev, "%s:Failed to resume display\n" + , __func__); + ddev->set_synchronized_update(ddev, + ddev->get_synchronized_update(ddev)); + return ret; +} + +static int sony_acx424akp_suspend(struct mcde_display_device *ddev, \ + pm_message_t state) +{ + int ret; + + /* set_power_mode will handle call platform_disable */ + ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF); + if (ret < 0) + dev_warn(&ddev->dev, "%s:Failed to suspend display\n" + , __func__); + return ret; +} +#endif + +static struct mcde_display_driver sony_acx424akp_driver = { + .probe = sony_acx424akp_probe, + .remove = sony_acx424akp_remove, +#if !defined(CONFIG_HAS_EARLYSUSPEND) && defined(CONFIG_PM) + .suspend = sony_acx424akp_suspend, + .resume = sony_acx424akp_resume, +#else + .suspend = NULL, + .resume = NULL, +#endif + .driver = { + .name = "mcde_disp_sony_acx424akp", + }, +}; + +/* Module init */ +static int __init mcde_display_sony_acx424akp_init(void) +{ + pr_info("%s\n", __func__); + + return mcde_display_driver_register(&sony_acx424akp_driver); +} +module_init(mcde_display_sony_acx424akp_init); + +static void __exit mcde_display_sony_acx424akp_exit(void) +{ + pr_info("%s\n", __func__); + + mcde_display_driver_unregister(&sony_acx424akp_driver); +} +module_exit(mcde_display_sony_acx424akp_exit); + +MODULE_AUTHOR("Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ST-Ericsson MCDE Sony ACX424AKP DCS display driver"); diff --git a/drivers/video/mcde/display-vuib500-dpi.c b/drivers/video/mcde/display-vuib500-dpi.c new file mode 100644 index 00000000000..2bd5b990608 --- /dev/null +++ b/drivers/video/mcde/display-vuib500-dpi.c @@ -0,0 +1,215 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson MCDE DPI display driver + * The VUIB500 is an user interface board the can be attached to an HREF. It + * supports the DPI pixel interface and converts this to an analog VGA signal, + * which can be connected to a monitor using a DSUB connector. The VUIB board + * uses an external power supply of 5V. + * + * Author: Marcel Tunnissen <marcel.tuennissen@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/gpio.h> + +#include <video/mcde_display.h> +#include <video/mcde_display-vuib500-dpi.h> + +#define DPI_DISP_TRACE dev_dbg(&ddev->dev, "%s\n", __func__) + +static int try_video_mode(struct mcde_display_device *ddev, + struct mcde_video_mode *video_mode); +static int set_video_mode(struct mcde_display_device *ddev, + struct mcde_video_mode *video_mode); + +static int __devinit dpi_display_probe(struct mcde_display_device *ddev) +{ + int ret = 0; + struct mcde_display_dpi_platform_data *pdata = ddev->dev.platform_data; + DPI_DISP_TRACE; + + if (pdata == NULL) { + dev_err(&ddev->dev, "%s:Platform data missing\n", __func__); + ret = -EINVAL; + goto no_pdata; + } + + if (ddev->port->type != MCDE_PORTTYPE_DPI) { + dev_err(&ddev->dev, + "%s:Invalid port type %d\n", + __func__, ddev->port->type); + ret = -EINVAL; + goto invalid_port_type; + } + + ddev->try_video_mode = try_video_mode; + ddev->set_video_mode = set_video_mode; + dev_info(&ddev->dev, "DPI display probed\n"); + + goto out; +invalid_port_type: +no_pdata: +out: + return ret; +} + +static int __devexit dpi_display_remove(struct mcde_display_device *ddev) +{ + DPI_DISP_TRACE; + + ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF); + + return 0; +} + +static int dpi_display_resume(struct mcde_display_device *ddev) +{ + int ret; + DPI_DISP_TRACE; + + /* set_power_mode will handle call platform_enable */ + ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY); + if (ret < 0) + dev_warn(&ddev->dev, "%s:Failed to resume display\n" + , __func__); + return ret; +} + +static int dpi_display_suspend(struct mcde_display_device *ddev, + pm_message_t state) +{ + int ret; + DPI_DISP_TRACE; + + /* set_power_mode will handle call platform_disable */ + ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF); + if (ret < 0) + dev_warn(&ddev->dev, "%s:Failed to suspend display\n" + , __func__); + return ret; +} + +static void print_vmode(struct mcde_video_mode *vmode) +{ + pr_debug("resolution: %dx%d\n", vmode->xres, vmode->yres); + pr_debug(" pixclock: %d\n", vmode->pixclock); + pr_debug(" hbp: %d\n", vmode->hbp); + pr_debug(" hfp: %d\n", vmode->hfp); + pr_debug(" hsw: %d\n", vmode->hsw); + pr_debug(" vbp: %d\n", vmode->vbp); + pr_debug(" vfp: %d\n", vmode->vfp); + pr_debug(" vsw: %d\n", vmode->vsw); + pr_debug("interlaced: %s\n", vmode->interlaced ? "true" : "false"); +} + +/* Taken from the programmed value of the LCD clock in PRCMU */ +#define PIX_CLK_FREQ 25000000 +#define VMODE_XRES 640 +#define VMODE_YRES 480 + +static int try_video_mode( + struct mcde_display_device *ddev, struct mcde_video_mode *video_mode) +{ + int res = -EINVAL; + DPI_DISP_TRACE; + + if (ddev == NULL || video_mode == NULL) { + dev_warn(&ddev->dev, "%s:ddev = NULL or video_mode = NULL\n", + __func__); + return res; + } + + if (video_mode->xres == VMODE_XRES && video_mode->yres == VMODE_YRES) { + video_mode->hbp = 40; + video_mode->hfp = 8; + video_mode->hsw = 96; + video_mode->vbp = 25; + video_mode->vfp = 2; + video_mode->vsw = 2; + /* + * The pixclock setting is not used within MCDE. The clock is + * setup elsewhere. But the pixclock value is visible in user + * space. + */ + video_mode->pixclock = (int) (1e+12 * (1.0 / PIX_CLK_FREQ)); + res = 0; + } /* TODO: add more supported resolutions here */ + video_mode->interlaced = false; + + if (res == 0) + print_vmode(video_mode); + else + dev_warn(&ddev->dev, + "%s:Failed to find video mode x=%d, y=%d\n", + __func__, video_mode->xres, video_mode->yres); + + return res; + +} + +static int set_video_mode( + struct mcde_display_device *ddev, struct mcde_video_mode *video_mode) +{ + int res; + DPI_DISP_TRACE; + + if (ddev == NULL || video_mode == NULL) { + dev_warn(&ddev->dev, "%s:ddev = NULL or video_mode = NULL\n", + __func__); + return -EINVAL; + } + if (video_mode->xres != VMODE_XRES || video_mode->yres != VMODE_YRES) { + dev_warn(&ddev->dev, "%s:Failed to set video mode x=%d, y=%d\n", + __func__, video_mode->xres, video_mode->yres); + return -EINVAL; + } + ddev->video_mode = *video_mode; + print_vmode(video_mode); + + res = mcde_chnl_set_video_mode(ddev->chnl_state, &ddev->video_mode); + if (res < 0) { + dev_warn(&ddev->dev, "%s:Failed to set video mode on channel\n", + __func__); + + } + /* notify mcde display driver about updated video mode */ + ddev->update_flags |= UPDATE_FLAG_VIDEO_MODE; + return res; +} + +static struct mcde_display_driver dpi_display_driver = { + .probe = dpi_display_probe, + .remove = dpi_display_remove, + .suspend = dpi_display_suspend, + .resume = dpi_display_resume, + .driver = { + .name = "mcde_display_dpi", + }, +}; + +/* Module init */ +static int __init mcde_dpi_display_init(void) +{ + pr_info("%s\n", __func__); + + return mcde_display_driver_register(&dpi_display_driver); +} +module_init(mcde_dpi_display_init); + +static void __exit mcde_dpi_display_exit(void) +{ + pr_info("%s\n", __func__); + + mcde_display_driver_unregister(&dpi_display_driver); +} +module_exit(mcde_dpi_display_exit); + +MODULE_AUTHOR("Marcel Tunnissen <marcel.tuennissen@stericsson.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ST-Ericsson MCDE DPI display driver fro VUIB500 display"); diff --git a/drivers/video/mcde/dsilink_regs.h b/drivers/video/mcde/dsilink_regs.h new file mode 100644 index 00000000000..29fa75a1752 --- /dev/null +++ b/drivers/video/mcde/dsilink_regs.h @@ -0,0 +1,2037 @@ + +#define DSI_VAL2REG(__reg, __fld, __val) \ + (((__val) << __reg##_##__fld##_SHIFT) & __reg##_##__fld##_MASK) +#define DSI_REG2VAL(__reg, __fld, __val) \ + (((__val) & __reg##_##__fld##_MASK) >> __reg##_##__fld##_SHIFT) + +#define DSI_MCTL_INTEGRATION_MODE 0x00000000 +#define DSI_MCTL_INTEGRATION_MODE_INT_MODE_EN_SHIFT 0 +#define DSI_MCTL_INTEGRATION_MODE_INT_MODE_EN_MASK 0x00000001 +#define DSI_MCTL_INTEGRATION_MODE_INT_MODE_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_INTEGRATION_MODE, INT_MODE_EN, __x) +#define DSI_MCTL_MAIN_DATA_CTL 0x00000004 +#define DSI_MCTL_MAIN_DATA_CTL_LINK_EN_SHIFT 0 +#define DSI_MCTL_MAIN_DATA_CTL_LINK_EN_MASK 0x00000001 +#define DSI_MCTL_MAIN_DATA_CTL_LINK_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, LINK_EN, __x) +#define DSI_MCTL_MAIN_DATA_CTL_IF1_MODE_SHIFT 1 +#define DSI_MCTL_MAIN_DATA_CTL_IF1_MODE_MASK 0x00000002 +#define DSI_MCTL_MAIN_DATA_CTL_IF1_MODE_CMD 0 +#define DSI_MCTL_MAIN_DATA_CTL_IF1_MODE_VID 1 +#define DSI_MCTL_MAIN_DATA_CTL_IF1_MODE_ENUM(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, IF1_MODE, \ + DSI_MCTL_MAIN_DATA_CTL_IF1_MODE_##__x) +#define DSI_MCTL_MAIN_DATA_CTL_IF1_MODE(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, IF1_MODE, __x) +#define DSI_MCTL_MAIN_DATA_CTL_VID_EN_SHIFT 2 +#define DSI_MCTL_MAIN_DATA_CTL_VID_EN_MASK 0x00000004 +#define DSI_MCTL_MAIN_DATA_CTL_VID_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, VID_EN, __x) +#define DSI_MCTL_MAIN_DATA_CTL_TVG_SEL_SHIFT 3 +#define DSI_MCTL_MAIN_DATA_CTL_TVG_SEL_MASK 0x00000008 +#define DSI_MCTL_MAIN_DATA_CTL_TVG_SEL(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, TVG_SEL, __x) +#define DSI_MCTL_MAIN_DATA_CTL_TBG_SEL_SHIFT 4 +#define DSI_MCTL_MAIN_DATA_CTL_TBG_SEL_MASK 0x00000010 +#define DSI_MCTL_MAIN_DATA_CTL_TBG_SEL(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, TBG_SEL, __x) +#define DSI_MCTL_MAIN_DATA_CTL_IF1_TE_EN_SHIFT 5 +#define DSI_MCTL_MAIN_DATA_CTL_IF1_TE_EN_MASK 0x00000020 +#define DSI_MCTL_MAIN_DATA_CTL_IF1_TE_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, IF1_TE_EN, __x) +#define DSI_MCTL_MAIN_DATA_CTL_IF2_TE_EN_SHIFT 6 +#define DSI_MCTL_MAIN_DATA_CTL_IF2_TE_EN_MASK 0x00000040 +#define DSI_MCTL_MAIN_DATA_CTL_IF2_TE_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, IF2_TE_EN, __x) +#define DSI_MCTL_MAIN_DATA_CTL_REG_TE_EN_SHIFT 7 +#define DSI_MCTL_MAIN_DATA_CTL_REG_TE_EN_MASK 0x00000080 +#define DSI_MCTL_MAIN_DATA_CTL_REG_TE_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, REG_TE_EN, __x) +#define DSI_MCTL_MAIN_DATA_CTL_READ_EN_SHIFT 8 +#define DSI_MCTL_MAIN_DATA_CTL_READ_EN_MASK 0x00000100 +#define DSI_MCTL_MAIN_DATA_CTL_READ_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, READ_EN, __x) +#define DSI_MCTL_MAIN_DATA_CTL_BTA_EN_SHIFT 9 +#define DSI_MCTL_MAIN_DATA_CTL_BTA_EN_MASK 0x00000200 +#define DSI_MCTL_MAIN_DATA_CTL_BTA_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, BTA_EN, __x) +#define DSI_MCTL_MAIN_DATA_CTL_DISP_GEN_ECC_SHIFT 10 +#define DSI_MCTL_MAIN_DATA_CTL_DISP_GEN_ECC_MASK 0x00000400 +#define DSI_MCTL_MAIN_DATA_CTL_DISP_GEN_ECC(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, DISP_GEN_ECC, __x) +#define DSI_MCTL_MAIN_DATA_CTL_DISP_GEN_CHECKSUM_SHIFT 11 +#define DSI_MCTL_MAIN_DATA_CTL_DISP_GEN_CHECKSUM_MASK 0x00000800 +#define DSI_MCTL_MAIN_DATA_CTL_DISP_GEN_CHECKSUM(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, DISP_GEN_CHECKSUM, __x) +#define DSI_MCTL_MAIN_DATA_CTL_HOST_EOT_GEN_SHIFT 12 +#define DSI_MCTL_MAIN_DATA_CTL_HOST_EOT_GEN_MASK 0x00001000 +#define DSI_MCTL_MAIN_DATA_CTL_HOST_EOT_GEN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, HOST_EOT_GEN, __x) +#define DSI_MCTL_MAIN_DATA_CTL_DISP_EOT_GEN_SHIFT 13 +#define DSI_MCTL_MAIN_DATA_CTL_DISP_EOT_GEN_MASK 0x00002000 +#define DSI_MCTL_MAIN_DATA_CTL_DISP_EOT_GEN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, DISP_EOT_GEN, __x) +#define DSI_MCTL_MAIN_DATA_CTL_DLX_REMAP_EN_SHIFT 14 +#define DSI_MCTL_MAIN_DATA_CTL_DLX_REMAP_EN_MASK 0x00004000 +#define DSI_MCTL_MAIN_DATA_CTL_DLX_REMAP_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, DLX_REMAP_EN, __x) +#define DSI_MCTL_MAIN_DATA_CTL_TE_POLLING_EN_SHIFT 15 +#define DSI_MCTL_MAIN_DATA_CTL_TE_POLLING_EN_MASK 0x00008000 +#define DSI_MCTL_MAIN_DATA_CTL_TE_POLLING_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_DATA_CTL, TE_POLLING_EN, __x) +#define DSI_MCTL_MAIN_PHY_CTL 0x00000008 +#define DSI_MCTL_MAIN_PHY_CTL_LANE2_EN_SHIFT 0 +#define DSI_MCTL_MAIN_PHY_CTL_LANE2_EN_MASK 0x00000001 +#define DSI_MCTL_MAIN_PHY_CTL_LANE2_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_PHY_CTL, LANE2_EN, __x) +#define DSI_MCTL_MAIN_PHY_CTL_FORCE_STOP_MODE_SHIFT 1 +#define DSI_MCTL_MAIN_PHY_CTL_FORCE_STOP_MODE_MASK 0x00000002 +#define DSI_MCTL_MAIN_PHY_CTL_FORCE_STOP_MODE(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_PHY_CTL, FORCE_STOP_MODE, __x) +#define DSI_MCTL_MAIN_PHY_CTL_CLK_CONTINUOUS_SHIFT 2 +#define DSI_MCTL_MAIN_PHY_CTL_CLK_CONTINUOUS_MASK 0x00000004 +#define DSI_MCTL_MAIN_PHY_CTL_CLK_CONTINUOUS(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_PHY_CTL, CLK_CONTINUOUS, __x) +#define DSI_MCTL_MAIN_PHY_CTL_CLK_ULPM_EN_SHIFT 3 +#define DSI_MCTL_MAIN_PHY_CTL_CLK_ULPM_EN_MASK 0x00000008 +#define DSI_MCTL_MAIN_PHY_CTL_CLK_ULPM_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_PHY_CTL, CLK_ULPM_EN, __x) +#define DSI_MCTL_MAIN_PHY_CTL_DAT1_ULPM_EN_SHIFT 4 +#define DSI_MCTL_MAIN_PHY_CTL_DAT1_ULPM_EN_MASK 0x00000010 +#define DSI_MCTL_MAIN_PHY_CTL_DAT1_ULPM_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_PHY_CTL, DAT1_ULPM_EN, __x) +#define DSI_MCTL_MAIN_PHY_CTL_DAT2_ULPM_EN_SHIFT 5 +#define DSI_MCTL_MAIN_PHY_CTL_DAT2_ULPM_EN_MASK 0x00000020 +#define DSI_MCTL_MAIN_PHY_CTL_DAT2_ULPM_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_PHY_CTL, DAT2_ULPM_EN, __x) +#define DSI_MCTL_MAIN_PHY_CTL_WAIT_BURST_TIME_SHIFT 6 +#define DSI_MCTL_MAIN_PHY_CTL_WAIT_BURST_TIME_MASK 0x000003C0 +#define DSI_MCTL_MAIN_PHY_CTL_WAIT_BURST_TIME(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_PHY_CTL, WAIT_BURST_TIME, __x) +#define DSI_MCTL_PLL_CTL 0x0000000C +#define DSI_MCTL_PLL_CTL_PLL_MULT_SHIFT 0 +#define DSI_MCTL_PLL_CTL_PLL_MULT_MASK 0x000000FF +#define DSI_MCTL_PLL_CTL_PLL_MULT(__x) \ + DSI_VAL2REG(DSI_MCTL_PLL_CTL, PLL_MULT, __x) +#define DSI_MCTL_PLL_CTL_PLL_OUT_DIV_SHIFT 8 +#define DSI_MCTL_PLL_CTL_PLL_OUT_DIV_MASK 0x00003F00 +#define DSI_MCTL_PLL_CTL_PLL_OUT_DIV(__x) \ + DSI_VAL2REG(DSI_MCTL_PLL_CTL, PLL_OUT_DIV, __x) +#define DSI_MCTL_PLL_CTL_PLL_IN_DIV_SHIFT 14 +#define DSI_MCTL_PLL_CTL_PLL_IN_DIV_MASK 0x0001C000 +#define DSI_MCTL_PLL_CTL_PLL_IN_DIV(__x) \ + DSI_VAL2REG(DSI_MCTL_PLL_CTL, PLL_IN_DIV, __x) +#define DSI_MCTL_PLL_CTL_PLL_SEL_DIV2_SHIFT 17 +#define DSI_MCTL_PLL_CTL_PLL_SEL_DIV2_MASK 0x00020000 +#define DSI_MCTL_PLL_CTL_PLL_SEL_DIV2(__x) \ + DSI_VAL2REG(DSI_MCTL_PLL_CTL, PLL_SEL_DIV2, __x) +#define DSI_MCTL_PLL_CTL_PLL_OUT_SEL_SHIFT 18 +#define DSI_MCTL_PLL_CTL_PLL_OUT_SEL_MASK 0x00040000 +#define DSI_MCTL_PLL_CTL_PLL_OUT_SEL_INT_PLL 0 +#define DSI_MCTL_PLL_CTL_PLL_OUT_SEL_SYS_PLL 1 +#define DSI_MCTL_PLL_CTL_PLL_OUT_SEL_ENUM(__x) \ + DSI_VAL2REG(DSI_MCTL_PLL_CTL, PLL_OUT_SEL, \ + DSI_MCTL_PLL_CTL_PLL_OUT_SEL_##__x) +#define DSI_MCTL_PLL_CTL_PLL_OUT_SEL(__x) \ + DSI_VAL2REG(DSI_MCTL_PLL_CTL, PLL_OUT_SEL, __x) +#define DSI_MCTL_PLL_CTL_PLL_MASTER_SHIFT 31 +#define DSI_MCTL_PLL_CTL_PLL_MASTER_MASK 0x80000000 +#define DSI_MCTL_PLL_CTL_PLL_MASTER(__x) \ + DSI_VAL2REG(DSI_MCTL_PLL_CTL, PLL_MASTER, __x) +#define DSI_MCTL_LANE_STS 0x00000010 +#define DSI_MCTL_LANE_STS_CLKLANE_STATE_SHIFT 0 +#define DSI_MCTL_LANE_STS_CLKLANE_STATE_MASK 0x00000003 +#define DSI_MCTL_LANE_STS_CLKLANE_STATE_START 0 +#define DSI_MCTL_LANE_STS_CLKLANE_STATE_IDLE 1 +#define DSI_MCTL_LANE_STS_CLKLANE_STATE_HS 2 +#define DSI_MCTL_LANE_STS_CLKLANE_STATE_ULPM 3 +#define DSI_MCTL_LANE_STS_CLKLANE_STATE_ENUM(__x) \ + DSI_VAL2REG(DSI_MCTL_LANE_STS, CLKLANE_STATE, \ + DSI_MCTL_LANE_STS_CLKLANE_STATE_##__x) +#define DSI_MCTL_LANE_STS_CLKLANE_STATE(__x) \ + DSI_VAL2REG(DSI_MCTL_LANE_STS, CLKLANE_STATE, __x) +#define DSI_MCTL_LANE_STS_DATLANE1_STATE_SHIFT 2 +#define DSI_MCTL_LANE_STS_DATLANE1_STATE_MASK 0x0000001C +#define DSI_MCTL_LANE_STS_DATLANE1_STATE_START 0 +#define DSI_MCTL_LANE_STS_DATLANE1_STATE_IDLE 1 +#define DSI_MCTL_LANE_STS_DATLANE1_STATE_WRITE 2 +#define DSI_MCTL_LANE_STS_DATLANE1_STATE_ULPM 3 +#define DSI_MCTL_LANE_STS_DATLANE1_STATE_READ 4 +#define DSI_MCTL_LANE_STS_DATLANE1_STATE_ENUM(__x) \ + DSI_VAL2REG(DSI_MCTL_LANE_STS, DATLANE1_STATE, \ + DSI_MCTL_LANE_STS_DATLANE1_STATE_##__x) +#define DSI_MCTL_LANE_STS_DATLANE1_STATE(__x) \ + DSI_VAL2REG(DSI_MCTL_LANE_STS, DATLANE1_STATE, __x) +#define DSI_MCTL_LANE_STS_DATLANE2_STATE_SHIFT 5 +#define DSI_MCTL_LANE_STS_DATLANE2_STATE_MASK 0x00000060 +#define DSI_MCTL_LANE_STS_DATLANE2_STATE_START 0 +#define DSI_MCTL_LANE_STS_DATLANE2_STATE_IDLE 1 +#define DSI_MCTL_LANE_STS_DATLANE2_STATE_WRITE 2 +#define DSI_MCTL_LANE_STS_DATLANE2_STATE_ULPM 3 +#define DSI_MCTL_LANE_STS_DATLANE2_STATE_ENUM(__x) \ + DSI_VAL2REG(DSI_MCTL_LANE_STS, DATLANE2_STATE, \ + DSI_MCTL_LANE_STS_DATLANE2_STATE_##__x) +#define DSI_MCTL_LANE_STS_DATLANE2_STATE(__x) \ + DSI_VAL2REG(DSI_MCTL_LANE_STS, DATLANE2_STATE, __x) +#define DSI_MCTL_DPHY_TIMEOUT 0x00000014 +#define DSI_MCTL_DPHY_TIMEOUT_CLK_DIV_SHIFT 0 +#define DSI_MCTL_DPHY_TIMEOUT_CLK_DIV_MASK 0x0000000F +#define DSI_MCTL_DPHY_TIMEOUT_CLK_DIV(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_TIMEOUT, CLK_DIV, __x) +#define DSI_MCTL_DPHY_TIMEOUT_HSTX_TO_VAL_SHIFT 4 +#define DSI_MCTL_DPHY_TIMEOUT_HSTX_TO_VAL_MASK 0x0003FFF0 +#define DSI_MCTL_DPHY_TIMEOUT_HSTX_TO_VAL(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_TIMEOUT, HSTX_TO_VAL, __x) +#define DSI_MCTL_DPHY_TIMEOUT_LPRX_TO_VAL_SHIFT 18 +#define DSI_MCTL_DPHY_TIMEOUT_LPRX_TO_VAL_MASK 0xFFFC0000 +#define DSI_MCTL_DPHY_TIMEOUT_LPRX_TO_VAL(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_TIMEOUT, LPRX_TO_VAL, __x) +#define DSI_MCTL_ULPOUT_TIME 0x00000018 +#define DSI_MCTL_ULPOUT_TIME_CKLANE_ULPOUT_TIME_SHIFT 0 +#define DSI_MCTL_ULPOUT_TIME_CKLANE_ULPOUT_TIME_MASK 0x000001FF +#define DSI_MCTL_ULPOUT_TIME_CKLANE_ULPOUT_TIME(__x) \ + DSI_VAL2REG(DSI_MCTL_ULPOUT_TIME, CKLANE_ULPOUT_TIME, __x) +#define DSI_MCTL_ULPOUT_TIME_DATA_ULPOUT_TIME_SHIFT 9 +#define DSI_MCTL_ULPOUT_TIME_DATA_ULPOUT_TIME_MASK 0x0003FE00 +#define DSI_MCTL_ULPOUT_TIME_DATA_ULPOUT_TIME(__x) \ + DSI_VAL2REG(DSI_MCTL_ULPOUT_TIME, DATA_ULPOUT_TIME, __x) +#define DSI_MCTL_DPHY_STATIC 0x0000001C +#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_CLK_SHIFT 0 +#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_CLK_MASK 0x00000001 +#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_CLK(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_STATIC, SWAP_PINS_CLK, __x) +#define DSI_MCTL_DPHY_STATIC_HS_INVERT_CLK_SHIFT 1 +#define DSI_MCTL_DPHY_STATIC_HS_INVERT_CLK_MASK 0x00000002 +#define DSI_MCTL_DPHY_STATIC_HS_INVERT_CLK(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_STATIC, HS_INVERT_CLK, __x) +#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_DAT1_SHIFT 2 +#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_DAT1_MASK 0x00000004 +#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_DAT1(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_STATIC, SWAP_PINS_DAT1, __x) +#define DSI_MCTL_DPHY_STATIC_HS_INVERT_DAT1_SHIFT 3 +#define DSI_MCTL_DPHY_STATIC_HS_INVERT_DAT1_MASK 0x00000008 +#define DSI_MCTL_DPHY_STATIC_HS_INVERT_DAT1(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_STATIC, HS_INVERT_DAT1, __x) +#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_DAT2_SHIFT 4 +#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_DAT2_MASK 0x00000010 +#define DSI_MCTL_DPHY_STATIC_SWAP_PINS_DAT2(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_STATIC, SWAP_PINS_DAT2, __x) +#define DSI_MCTL_DPHY_STATIC_HS_INVERT_DAT2_SHIFT 5 +#define DSI_MCTL_DPHY_STATIC_HS_INVERT_DAT2_MASK 0x00000020 +#define DSI_MCTL_DPHY_STATIC_HS_INVERT_DAT2(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_STATIC, HS_INVERT_DAT2, __x) +#define DSI_MCTL_DPHY_STATIC_UI_X4_SHIFT 6 +#define DSI_MCTL_DPHY_STATIC_UI_X4_MASK 0x00000FC0 +#define DSI_MCTL_DPHY_STATIC_UI_X4(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_STATIC, UI_X4, __x) +#define DSI_MCTL_MAIN_EN 0x00000020 +#define DSI_MCTL_MAIN_EN_PLL_START_SHIFT 0 +#define DSI_MCTL_MAIN_EN_PLL_START_MASK 0x00000001 +#define DSI_MCTL_MAIN_EN_PLL_START(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_EN, PLL_START, __x) +#define DSI_MCTL_MAIN_EN_CKLANE_EN_SHIFT 3 +#define DSI_MCTL_MAIN_EN_CKLANE_EN_MASK 0x00000008 +#define DSI_MCTL_MAIN_EN_CKLANE_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_EN, CKLANE_EN, __x) +#define DSI_MCTL_MAIN_EN_DAT1_EN_SHIFT 4 +#define DSI_MCTL_MAIN_EN_DAT1_EN_MASK 0x00000010 +#define DSI_MCTL_MAIN_EN_DAT1_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_EN, DAT1_EN, __x) +#define DSI_MCTL_MAIN_EN_DAT2_EN_SHIFT 5 +#define DSI_MCTL_MAIN_EN_DAT2_EN_MASK 0x00000020 +#define DSI_MCTL_MAIN_EN_DAT2_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_EN, DAT2_EN, __x) +#define DSI_MCTL_MAIN_EN_CLKLANE_ULPM_REQ_SHIFT 6 +#define DSI_MCTL_MAIN_EN_CLKLANE_ULPM_REQ_MASK 0x00000040 +#define DSI_MCTL_MAIN_EN_CLKLANE_ULPM_REQ(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_EN, CLKLANE_ULPM_REQ, __x) +#define DSI_MCTL_MAIN_EN_DAT1_ULPM_REQ_SHIFT 7 +#define DSI_MCTL_MAIN_EN_DAT1_ULPM_REQ_MASK 0x00000080 +#define DSI_MCTL_MAIN_EN_DAT1_ULPM_REQ(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_EN, DAT1_ULPM_REQ, __x) +#define DSI_MCTL_MAIN_EN_DAT2_ULPM_REQ_SHIFT 8 +#define DSI_MCTL_MAIN_EN_DAT2_ULPM_REQ_MASK 0x00000100 +#define DSI_MCTL_MAIN_EN_DAT2_ULPM_REQ(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_EN, DAT2_ULPM_REQ, __x) +#define DSI_MCTL_MAIN_EN_IF1_EN_SHIFT 9 +#define DSI_MCTL_MAIN_EN_IF1_EN_MASK 0x00000200 +#define DSI_MCTL_MAIN_EN_IF1_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_EN, IF1_EN, __x) +#define DSI_MCTL_MAIN_EN_IF2_EN_SHIFT 10 +#define DSI_MCTL_MAIN_EN_IF2_EN_MASK 0x00000400 +#define DSI_MCTL_MAIN_EN_IF2_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_EN, IF2_EN, __x) +#define DSI_MCTL_MAIN_STS 0x00000024 +#define DSI_MCTL_MAIN_STS_PLL_LOCK_SHIFT 0 +#define DSI_MCTL_MAIN_STS_PLL_LOCK_MASK 0x00000001 +#define DSI_MCTL_MAIN_STS_PLL_LOCK(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS, PLL_LOCK, __x) +#define DSI_MCTL_MAIN_STS_CLKLANE_READY_SHIFT 1 +#define DSI_MCTL_MAIN_STS_CLKLANE_READY_MASK 0x00000002 +#define DSI_MCTL_MAIN_STS_CLKLANE_READY(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS, CLKLANE_READY, __x) +#define DSI_MCTL_MAIN_STS_DAT1_READY_SHIFT 2 +#define DSI_MCTL_MAIN_STS_DAT1_READY_MASK 0x00000004 +#define DSI_MCTL_MAIN_STS_DAT1_READY(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS, DAT1_READY, __x) +#define DSI_MCTL_MAIN_STS_DAT2_READY_SHIFT 3 +#define DSI_MCTL_MAIN_STS_DAT2_READY_MASK 0x00000008 +#define DSI_MCTL_MAIN_STS_DAT2_READY(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS, DAT2_READY, __x) +#define DSI_MCTL_MAIN_STS_HSTX_TO_ERR_SHIFT 4 +#define DSI_MCTL_MAIN_STS_HSTX_TO_ERR_MASK 0x00000010 +#define DSI_MCTL_MAIN_STS_HSTX_TO_ERR(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS, HSTX_TO_ERR, __x) +#define DSI_MCTL_MAIN_STS_LPRX_TO_ERR_SHIFT 5 +#define DSI_MCTL_MAIN_STS_LPRX_TO_ERR_MASK 0x00000020 +#define DSI_MCTL_MAIN_STS_LPRX_TO_ERR(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS, LPRX_TO_ERR, __x) +#define DSI_MCTL_MAIN_STS_CRS_UNTERM_PCK_SHIFT 6 +#define DSI_MCTL_MAIN_STS_CRS_UNTERM_PCK_MASK 0x00000040 +#define DSI_MCTL_MAIN_STS_CRS_UNTERM_PCK(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS, CRS_UNTERM_PCK, __x) +#define DSI_MCTL_MAIN_STS_VRS_UNTERM_PCK_SHIFT 7 +#define DSI_MCTL_MAIN_STS_VRS_UNTERM_PCK_MASK 0x00000080 +#define DSI_MCTL_MAIN_STS_VRS_UNTERM_PCK(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS, VRS_UNTERM_PCK, __x) +#define DSI_MCTL_DPHY_ERR 0x00000028 +#define DSI_MCTL_DPHY_ERR_ERR_ESC_1_SHIFT 6 +#define DSI_MCTL_DPHY_ERR_ERR_ESC_1_MASK 0x00000040 +#define DSI_MCTL_DPHY_ERR_ERR_ESC_1(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_ESC_1, __x) +#define DSI_MCTL_DPHY_ERR_ERR_ESC_2_SHIFT 7 +#define DSI_MCTL_DPHY_ERR_ERR_ESC_2_MASK 0x00000080 +#define DSI_MCTL_DPHY_ERR_ERR_ESC_2(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_ESC_2, __x) +#define DSI_MCTL_DPHY_ERR_ERR_SYNCESC_1_SHIFT 8 +#define DSI_MCTL_DPHY_ERR_ERR_SYNCESC_1_MASK 0x00000100 +#define DSI_MCTL_DPHY_ERR_ERR_SYNCESC_1(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_SYNCESC_1, __x) +#define DSI_MCTL_DPHY_ERR_ERR_SYNCESC_2_SHIFT 9 +#define DSI_MCTL_DPHY_ERR_ERR_SYNCESC_2_MASK 0x00000200 +#define DSI_MCTL_DPHY_ERR_ERR_SYNCESC_2(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_SYNCESC_2, __x) +#define DSI_MCTL_DPHY_ERR_ERR_CONTROL_1_SHIFT 10 +#define DSI_MCTL_DPHY_ERR_ERR_CONTROL_1_MASK 0x00000400 +#define DSI_MCTL_DPHY_ERR_ERR_CONTROL_1(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_CONTROL_1, __x) +#define DSI_MCTL_DPHY_ERR_ERR_CONTROL_2_SHIFT 11 +#define DSI_MCTL_DPHY_ERR_ERR_CONTROL_2_MASK 0x00000800 +#define DSI_MCTL_DPHY_ERR_ERR_CONTROL_2(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_CONTROL_2, __x) +#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP0_1_SHIFT 12 +#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP0_1_MASK 0x00001000 +#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP0_1(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_CONT_LP0_1, __x) +#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP0_2_SHIFT 13 +#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP0_2_MASK 0x00002000 +#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP0_2(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_CONT_LP0_2, __x) +#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP1_1_SHIFT 14 +#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP1_1_MASK 0x00004000 +#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP1_1(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_CONT_LP1_1, __x) +#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP1_2_SHIFT 15 +#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP1_2_MASK 0x00008000 +#define DSI_MCTL_DPHY_ERR_ERR_CONT_LP1_2(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR, ERR_CONT_LP1_2, __x) +#define DSI_INT_VID_RDDATA 0x00000030 +#define DSI_INT_VID_RDDATA_IF_DATA_SHIFT 0 +#define DSI_INT_VID_RDDATA_IF_DATA_MASK 0x0000FFFF +#define DSI_INT_VID_RDDATA_IF_DATA(__x) \ + DSI_VAL2REG(DSI_INT_VID_RDDATA, IF_DATA, __x) +#define DSI_INT_VID_RDDATA_IF_VALID_SHIFT 16 +#define DSI_INT_VID_RDDATA_IF_VALID_MASK 0x00010000 +#define DSI_INT_VID_RDDATA_IF_VALID(__x) \ + DSI_VAL2REG(DSI_INT_VID_RDDATA, IF_VALID, __x) +#define DSI_INT_VID_RDDATA_IF_START_SHIFT 17 +#define DSI_INT_VID_RDDATA_IF_START_MASK 0x00020000 +#define DSI_INT_VID_RDDATA_IF_START(__x) \ + DSI_VAL2REG(DSI_INT_VID_RDDATA, IF_START, __x) +#define DSI_INT_VID_RDDATA_IF_FRAME_SYNC_SHIFT 18 +#define DSI_INT_VID_RDDATA_IF_FRAME_SYNC_MASK 0x00040000 +#define DSI_INT_VID_RDDATA_IF_FRAME_SYNC(__x) \ + DSI_VAL2REG(DSI_INT_VID_RDDATA, IF_FRAME_SYNC, __x) +#define DSI_INT_VID_GNT 0x00000034 +#define DSI_INT_VID_GNT_IF_STALL_SHIFT 0 +#define DSI_INT_VID_GNT_IF_STALL_MASK 0x00000001 +#define DSI_INT_VID_GNT_IF_STALL(__x) \ + DSI_VAL2REG(DSI_INT_VID_GNT, IF_STALL, __x) +#define DSI_INT_CMD_RDDATA 0x00000038 +#define DSI_INT_CMD_RDDATA_IF_DATA_SHIFT 0 +#define DSI_INT_CMD_RDDATA_IF_DATA_MASK 0x0000FFFF +#define DSI_INT_CMD_RDDATA_IF_DATA(__x) \ + DSI_VAL2REG(DSI_INT_CMD_RDDATA, IF_DATA, __x) +#define DSI_INT_CMD_RDDATA_IF_VALID_SHIFT 16 +#define DSI_INT_CMD_RDDATA_IF_VALID_MASK 0x00010000 +#define DSI_INT_CMD_RDDATA_IF_VALID(__x) \ + DSI_VAL2REG(DSI_INT_CMD_RDDATA, IF_VALID, __x) +#define DSI_INT_CMD_RDDATA_IF_START_SHIFT 17 +#define DSI_INT_CMD_RDDATA_IF_START_MASK 0x00020000 +#define DSI_INT_CMD_RDDATA_IF_START(__x) \ + DSI_VAL2REG(DSI_INT_CMD_RDDATA, IF_START, __x) +#define DSI_INT_CMD_RDDATA_IF_FRAME_SYNC_SHIFT 18 +#define DSI_INT_CMD_RDDATA_IF_FRAME_SYNC_MASK 0x00040000 +#define DSI_INT_CMD_RDDATA_IF_FRAME_SYNC(__x) \ + DSI_VAL2REG(DSI_INT_CMD_RDDATA, IF_FRAME_SYNC, __x) +#define DSI_INT_CMD_GNT 0x0000003C +#define DSI_INT_CMD_GNT_IF_STALL_SHIFT 0 +#define DSI_INT_CMD_GNT_IF_STALL_MASK 0x00000001 +#define DSI_INT_CMD_GNT_IF_STALL(__x) \ + DSI_VAL2REG(DSI_INT_CMD_GNT, IF_STALL, __x) +#define DSI_INT_INTERRUPT_CTL 0x00000040 +#define DSI_INT_INTERRUPT_CTL_INT_VAL_SHIFT 0 +#define DSI_INT_INTERRUPT_CTL_INT_VAL_MASK 0x00000001 +#define DSI_INT_INTERRUPT_CTL_INT_VAL(__x) \ + DSI_VAL2REG(DSI_INT_INTERRUPT_CTL, INT_VAL, __x) +#define DSI_CMD_MODE_CTL 0x00000050 +#define DSI_CMD_MODE_CTL_IF1_ID_SHIFT 0 +#define DSI_CMD_MODE_CTL_IF1_ID_MASK 0x00000003 +#define DSI_CMD_MODE_CTL_IF1_ID(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_CTL, IF1_ID, __x) +#define DSI_CMD_MODE_CTL_IF2_ID_SHIFT 2 +#define DSI_CMD_MODE_CTL_IF2_ID_MASK 0x0000000C +#define DSI_CMD_MODE_CTL_IF2_ID(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_CTL, IF2_ID, __x) +#define DSI_CMD_MODE_CTL_IF1_LP_EN_SHIFT 4 +#define DSI_CMD_MODE_CTL_IF1_LP_EN_MASK 0x00000010 +#define DSI_CMD_MODE_CTL_IF1_LP_EN(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_CTL, IF1_LP_EN, __x) +#define DSI_CMD_MODE_CTL_IF2_LP_EN_SHIFT 5 +#define DSI_CMD_MODE_CTL_IF2_LP_EN_MASK 0x00000020 +#define DSI_CMD_MODE_CTL_IF2_LP_EN(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_CTL, IF2_LP_EN, __x) +#define DSI_CMD_MODE_CTL_ARB_MODE_SHIFT 6 +#define DSI_CMD_MODE_CTL_ARB_MODE_MASK 0x00000040 +#define DSI_CMD_MODE_CTL_ARB_MODE(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_CTL, ARB_MODE, __x) +#define DSI_CMD_MODE_CTL_ARB_PRI_SHIFT 7 +#define DSI_CMD_MODE_CTL_ARB_PRI_MASK 0x00000080 +#define DSI_CMD_MODE_CTL_ARB_PRI(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_CTL, ARB_PRI, __x) +#define DSI_CMD_MODE_CTL_FIL_VALUE_SHIFT 8 +#define DSI_CMD_MODE_CTL_FIL_VALUE_MASK 0x0000FF00 +#define DSI_CMD_MODE_CTL_FIL_VALUE(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_CTL, FIL_VALUE, __x) +#define DSI_CMD_MODE_CTL_TE_TIMEOUT_SHIFT 16 +#define DSI_CMD_MODE_CTL_TE_TIMEOUT_MASK 0x03FF0000 +#define DSI_CMD_MODE_CTL_TE_TIMEOUT(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_CTL, TE_TIMEOUT, __x) +#define DSI_CMD_MODE_STS 0x00000054 +#define DSI_CMD_MODE_STS_ERR_NO_TE_SHIFT 0 +#define DSI_CMD_MODE_STS_ERR_NO_TE_MASK 0x00000001 +#define DSI_CMD_MODE_STS_ERR_NO_TE(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS, ERR_NO_TE, __x) +#define DSI_CMD_MODE_STS_ERR_TE_MISS_SHIFT 1 +#define DSI_CMD_MODE_STS_ERR_TE_MISS_MASK 0x00000002 +#define DSI_CMD_MODE_STS_ERR_TE_MISS(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS, ERR_TE_MISS, __x) +#define DSI_CMD_MODE_STS_ERR_SDI1_UNDERRUN_SHIFT 2 +#define DSI_CMD_MODE_STS_ERR_SDI1_UNDERRUN_MASK 0x00000004 +#define DSI_CMD_MODE_STS_ERR_SDI1_UNDERRUN(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS, ERR_SDI1_UNDERRUN, __x) +#define DSI_CMD_MODE_STS_ERR_SDI2_UNDERRUN_SHIFT 3 +#define DSI_CMD_MODE_STS_ERR_SDI2_UNDERRUN_MASK 0x00000008 +#define DSI_CMD_MODE_STS_ERR_SDI2_UNDERRUN(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS, ERR_SDI2_UNDERRUN, __x) +#define DSI_CMD_MODE_STS_ERR_UNWANTED_RD_SHIFT 4 +#define DSI_CMD_MODE_STS_ERR_UNWANTED_RD_MASK 0x00000010 +#define DSI_CMD_MODE_STS_ERR_UNWANTED_RD(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS, ERR_UNWANTED_RD, __x) +#define DSI_CMD_MODE_STS_CSM_RUNNING_SHIFT 5 +#define DSI_CMD_MODE_STS_CSM_RUNNING_MASK 0x00000020 +#define DSI_CMD_MODE_STS_CSM_RUNNING(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS, CSM_RUNNING, __x) +#define DSI_DIRECT_CMD_SEND 0x00000060 +#define DSI_DIRECT_CMD_SEND_START_SHIFT 0 +#define DSI_DIRECT_CMD_SEND_START_MASK 0xFFFFFFFF +#define DSI_DIRECT_CMD_SEND_START(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_SEND, START, __x) +#define DSI_DIRECT_CMD_MAIN_SETTINGS 0x00000064 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_SHIFT 0 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_MASK 0x00000007 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_WRITE 0 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_READ 1 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_TE_REQ 4 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_TRIG_REQ 5 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_BTA_REQ 6 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_ENUM(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_NAT, \ + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_##__x) +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_NAT, __x) +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT_SHIFT 3 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT_MASK 0x00000008 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_LONGNOTSHORT, __x) +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SHIFT 8 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_MASK 0x00003F00 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_GENERIC_SHORT_WRITE_0 3 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_GENERIC_SHORT_WRITE_1 19 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_GENERIC_SHORT_WRITE_2 35 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_GENERIC_LONG_WRITE 41 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_SHORT_WRITE_0 5 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_SHORT_WRITE_1 21 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_LONG_WRITE 57 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_DCS_READ 6 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_SET_MAX_PKT_SIZE 55 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_HEAD, \ + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_##__x) +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_HEAD, __x) +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_SHIFT 14 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID_MASK 0x0000C000 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_ID, __x) +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_SHIFT 16 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE_MASK 0x001F0000 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_SIZE, __x) +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN_SHIFT 21 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN_MASK 0x00200000 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, CMD_LP_EN, __x) +#define DSI_DIRECT_CMD_MAIN_SETTINGS_TRIGGER_VAL_SHIFT 24 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_TRIGGER_VAL_MASK 0x0F000000 +#define DSI_DIRECT_CMD_MAIN_SETTINGS_TRIGGER_VAL(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_MAIN_SETTINGS, TRIGGER_VAL, __x) +#define DSI_DIRECT_CMD_STS 0x00000068 +#define DSI_DIRECT_CMD_STS_CMD_TRANSMISSION_SHIFT 0 +#define DSI_DIRECT_CMD_STS_CMD_TRANSMISSION_MASK 0x00000001 +#define DSI_DIRECT_CMD_STS_CMD_TRANSMISSION(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS, CMD_TRANSMISSION, __x) +#define DSI_DIRECT_CMD_STS_WRITE_COMPLETED_SHIFT 1 +#define DSI_DIRECT_CMD_STS_WRITE_COMPLETED_MASK 0x00000002 +#define DSI_DIRECT_CMD_STS_WRITE_COMPLETED(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS, WRITE_COMPLETED, __x) +#define DSI_DIRECT_CMD_STS_TRIGGER_COMPLETED_SHIFT 2 +#define DSI_DIRECT_CMD_STS_TRIGGER_COMPLETED_MASK 0x00000004 +#define DSI_DIRECT_CMD_STS_TRIGGER_COMPLETED(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS, TRIGGER_COMPLETED, __x) +#define DSI_DIRECT_CMD_STS_READ_COMPLETED_SHIFT 3 +#define DSI_DIRECT_CMD_STS_READ_COMPLETED_MASK 0x00000008 +#define DSI_DIRECT_CMD_STS_READ_COMPLETED(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS, READ_COMPLETED, __x) +#define DSI_DIRECT_CMD_STS_ACKNOWLEDGE_RECEIVED_SHIFT 4 +#define DSI_DIRECT_CMD_STS_ACKNOWLEDGE_RECEIVED_MASK 0x00000010 +#define DSI_DIRECT_CMD_STS_ACKNOWLEDGE_RECEIVED(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS, ACKNOWLEDGE_RECEIVED, __x) +#define DSI_DIRECT_CMD_STS_ACKNOWLEDGE_WITH_ERR_RECEIVED_SHIFT 5 +#define DSI_DIRECT_CMD_STS_ACKNOWLEDGE_WITH_ERR_RECEIVED_MASK 0x00000020 +#define DSI_DIRECT_CMD_STS_ACKNOWLEDGE_WITH_ERR_RECEIVED(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS, ACKNOWLEDGE_WITH_ERR_RECEIVED, __x) +#define DSI_DIRECT_CMD_STS_TRIGGER_RECEIVED_SHIFT 6 +#define DSI_DIRECT_CMD_STS_TRIGGER_RECEIVED_MASK 0x00000040 +#define DSI_DIRECT_CMD_STS_TRIGGER_RECEIVED(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS, TRIGGER_RECEIVED, __x) +#define DSI_DIRECT_CMD_STS_TE_RECEIVED_SHIFT 7 +#define DSI_DIRECT_CMD_STS_TE_RECEIVED_MASK 0x00000080 +#define DSI_DIRECT_CMD_STS_TE_RECEIVED(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS, TE_RECEIVED, __x) +#define DSI_DIRECT_CMD_STS_BTA_COMPLETED_SHIFT 8 +#define DSI_DIRECT_CMD_STS_BTA_COMPLETED_MASK 0x00000100 +#define DSI_DIRECT_CMD_STS_BTA_COMPLETED(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS, BTA_COMPLETED, __x) +#define DSI_DIRECT_CMD_STS_BTA_FINISHED_SHIFT 9 +#define DSI_DIRECT_CMD_STS_BTA_FINISHED_MASK 0x00000200 +#define DSI_DIRECT_CMD_STS_BTA_FINISHED(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS, BTA_FINISHED, __x) +#define DSI_DIRECT_CMD_STS_READ_COMPLETED_WITH_ERR_SHIFT 10 +#define DSI_DIRECT_CMD_STS_READ_COMPLETED_WITH_ERR_MASK 0x00000400 +#define DSI_DIRECT_CMD_STS_READ_COMPLETED_WITH_ERR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS, READ_COMPLETED_WITH_ERR, __x) +#define DSI_DIRECT_CMD_STS_TRIGGER_VAL_SHIFT 11 +#define DSI_DIRECT_CMD_STS_TRIGGER_VAL_MASK 0x00007800 +#define DSI_DIRECT_CMD_STS_TRIGGER_VAL(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS, TRIGGER_VAL, __x) +#define DSI_DIRECT_CMD_STS_ACK_VAL_SHIFT 16 +#define DSI_DIRECT_CMD_STS_ACK_VAL_MASK 0xFFFF0000 +#define DSI_DIRECT_CMD_STS_ACK_VAL(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS, ACK_VAL, __x) +#define DSI_DIRECT_CMD_RD_INIT 0x0000006C +#define DSI_DIRECT_CMD_RD_INIT_RESET_SHIFT 0 +#define DSI_DIRECT_CMD_RD_INIT_RESET_MASK 0xFFFFFFFF +#define DSI_DIRECT_CMD_RD_INIT_RESET(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_INIT, RESET, __x) +#define DSI_DIRECT_CMD_WRDAT0 0x00000070 +#define DSI_DIRECT_CMD_WRDAT0_WRDAT0_SHIFT 0 +#define DSI_DIRECT_CMD_WRDAT0_WRDAT0_MASK 0x000000FF +#define DSI_DIRECT_CMD_WRDAT0_WRDAT0(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT0, WRDAT0, __x) +#define DSI_DIRECT_CMD_WRDAT0_WRDAT1_SHIFT 8 +#define DSI_DIRECT_CMD_WRDAT0_WRDAT1_MASK 0x0000FF00 +#define DSI_DIRECT_CMD_WRDAT0_WRDAT1(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT0, WRDAT1, __x) +#define DSI_DIRECT_CMD_WRDAT0_WRDAT2_SHIFT 16 +#define DSI_DIRECT_CMD_WRDAT0_WRDAT2_MASK 0x00FF0000 +#define DSI_DIRECT_CMD_WRDAT0_WRDAT2(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT0, WRDAT2, __x) +#define DSI_DIRECT_CMD_WRDAT0_WRDAT3_SHIFT 24 +#define DSI_DIRECT_CMD_WRDAT0_WRDAT3_MASK 0xFF000000 +#define DSI_DIRECT_CMD_WRDAT0_WRDAT3(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT0, WRDAT3, __x) +#define DSI_DIRECT_CMD_WRDAT1 0x00000074 +#define DSI_DIRECT_CMD_WRDAT1_WRDAT4_SHIFT 0 +#define DSI_DIRECT_CMD_WRDAT1_WRDAT4_MASK 0x000000FF +#define DSI_DIRECT_CMD_WRDAT1_WRDAT4(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT1, WRDAT4, __x) +#define DSI_DIRECT_CMD_WRDAT1_WRDAT5_SHIFT 8 +#define DSI_DIRECT_CMD_WRDAT1_WRDAT5_MASK 0x0000FF00 +#define DSI_DIRECT_CMD_WRDAT1_WRDAT5(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT1, WRDAT5, __x) +#define DSI_DIRECT_CMD_WRDAT1_WRDAT6_SHIFT 16 +#define DSI_DIRECT_CMD_WRDAT1_WRDAT6_MASK 0x00FF0000 +#define DSI_DIRECT_CMD_WRDAT1_WRDAT6(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT1, WRDAT6, __x) +#define DSI_DIRECT_CMD_WRDAT1_WRDAT7_SHIFT 24 +#define DSI_DIRECT_CMD_WRDAT1_WRDAT7_MASK 0xFF000000 +#define DSI_DIRECT_CMD_WRDAT1_WRDAT7(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT1, WRDAT7, __x) +#define DSI_DIRECT_CMD_WRDAT2 0x00000078 +#define DSI_DIRECT_CMD_WRDAT2_WRDAT8_SHIFT 0 +#define DSI_DIRECT_CMD_WRDAT2_WRDAT8_MASK 0x000000FF +#define DSI_DIRECT_CMD_WRDAT2_WRDAT8(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT2, WRDAT8, __x) +#define DSI_DIRECT_CMD_WRDAT2_WRDAT9_SHIFT 8 +#define DSI_DIRECT_CMD_WRDAT2_WRDAT9_MASK 0x0000FF00 +#define DSI_DIRECT_CMD_WRDAT2_WRDAT9(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT2, WRDAT9, __x) +#define DSI_DIRECT_CMD_WRDAT2_WRDAT10_SHIFT 16 +#define DSI_DIRECT_CMD_WRDAT2_WRDAT10_MASK 0x00FF0000 +#define DSI_DIRECT_CMD_WRDAT2_WRDAT10(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT2, WRDAT10, __x) +#define DSI_DIRECT_CMD_WRDAT2_WRDAT11_SHIFT 24 +#define DSI_DIRECT_CMD_WRDAT2_WRDAT11_MASK 0xFF000000 +#define DSI_DIRECT_CMD_WRDAT2_WRDAT11(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT2, WRDAT11, __x) +#define DSI_DIRECT_CMD_WRDAT3 0x0000007C +#define DSI_DIRECT_CMD_WRDAT3_WRDAT12_SHIFT 0 +#define DSI_DIRECT_CMD_WRDAT3_WRDAT12_MASK 0x000000FF +#define DSI_DIRECT_CMD_WRDAT3_WRDAT12(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT3, WRDAT12, __x) +#define DSI_DIRECT_CMD_WRDAT3_WRDAT13_SHIFT 8 +#define DSI_DIRECT_CMD_WRDAT3_WRDAT13_MASK 0x0000FF00 +#define DSI_DIRECT_CMD_WRDAT3_WRDAT13(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT3, WRDAT13, __x) +#define DSI_DIRECT_CMD_WRDAT3_WRDAT14_SHIFT 16 +#define DSI_DIRECT_CMD_WRDAT3_WRDAT14_MASK 0x00FF0000 +#define DSI_DIRECT_CMD_WRDAT3_WRDAT14(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT3, WRDAT14, __x) +#define DSI_DIRECT_CMD_WRDAT3_WRDAT15_SHIFT 24 +#define DSI_DIRECT_CMD_WRDAT3_WRDAT15_MASK 0xFF000000 +#define DSI_DIRECT_CMD_WRDAT3_WRDAT15(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_WRDAT3, WRDAT15, __x) +#define DSI_DIRECT_CMD_RDDAT 0x00000080 +#define DSI_DIRECT_CMD_RDDAT_RDDAT0_SHIFT 0 +#define DSI_DIRECT_CMD_RDDAT_RDDAT0_MASK 0x000000FF +#define DSI_DIRECT_CMD_RDDAT_RDDAT0(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RDDAT, RDDAT0, __x) +#define DSI_DIRECT_CMD_RDDAT_RDDAT1_SHIFT 8 +#define DSI_DIRECT_CMD_RDDAT_RDDAT1_MASK 0x0000FF00 +#define DSI_DIRECT_CMD_RDDAT_RDDAT1(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RDDAT, RDDAT1, __x) +#define DSI_DIRECT_CMD_RDDAT_RDDAT2_SHIFT 16 +#define DSI_DIRECT_CMD_RDDAT_RDDAT2_MASK 0x00FF0000 +#define DSI_DIRECT_CMD_RDDAT_RDDAT2(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RDDAT, RDDAT2, __x) +#define DSI_DIRECT_CMD_RDDAT_RDDAT3_SHIFT 24 +#define DSI_DIRECT_CMD_RDDAT_RDDAT3_MASK 0xFF000000 +#define DSI_DIRECT_CMD_RDDAT_RDDAT3(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RDDAT, RDDAT3, __x) +#define DSI_DIRECT_CMD_RD_PROPERTY 0x00000084 +#define DSI_DIRECT_CMD_RD_PROPERTY_RD_SIZE_SHIFT 0 +#define DSI_DIRECT_CMD_RD_PROPERTY_RD_SIZE_MASK 0x0000FFFF +#define DSI_DIRECT_CMD_RD_PROPERTY_RD_SIZE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_PROPERTY, RD_SIZE, __x) +#define DSI_DIRECT_CMD_RD_PROPERTY_RD_ID_SHIFT 16 +#define DSI_DIRECT_CMD_RD_PROPERTY_RD_ID_MASK 0x00030000 +#define DSI_DIRECT_CMD_RD_PROPERTY_RD_ID(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_PROPERTY, RD_ID, __x) +#define DSI_DIRECT_CMD_RD_PROPERTY_RD_DCSNOTGENERIC_SHIFT 18 +#define DSI_DIRECT_CMD_RD_PROPERTY_RD_DCSNOTGENERIC_MASK 0x00040000 +#define DSI_DIRECT_CMD_RD_PROPERTY_RD_DCSNOTGENERIC(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_PROPERTY, RD_DCSNOTGENERIC, __x) +#define DSI_DIRECT_CMD_RD_STS 0x00000088 +#define DSI_DIRECT_CMD_RD_STS_ERR_FIXED_SHIFT 0 +#define DSI_DIRECT_CMD_RD_STS_ERR_FIXED_MASK 0x00000001 +#define DSI_DIRECT_CMD_RD_STS_ERR_FIXED(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_FIXED, __x) +#define DSI_DIRECT_CMD_RD_STS_ERR_UNCORRECTABLE_SHIFT 1 +#define DSI_DIRECT_CMD_RD_STS_ERR_UNCORRECTABLE_MASK 0x00000002 +#define DSI_DIRECT_CMD_RD_STS_ERR_UNCORRECTABLE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_UNCORRECTABLE, __x) +#define DSI_DIRECT_CMD_RD_STS_ERR_CHECKSUM_SHIFT 2 +#define DSI_DIRECT_CMD_RD_STS_ERR_CHECKSUM_MASK 0x00000004 +#define DSI_DIRECT_CMD_RD_STS_ERR_CHECKSUM(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_CHECKSUM, __x) +#define DSI_DIRECT_CMD_RD_STS_ERR_UNDECODABLE_SHIFT 3 +#define DSI_DIRECT_CMD_RD_STS_ERR_UNDECODABLE_MASK 0x00000008 +#define DSI_DIRECT_CMD_RD_STS_ERR_UNDECODABLE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_UNDECODABLE, __x) +#define DSI_DIRECT_CMD_RD_STS_ERR_RECEIVE_SHIFT 4 +#define DSI_DIRECT_CMD_RD_STS_ERR_RECEIVE_MASK 0x00000010 +#define DSI_DIRECT_CMD_RD_STS_ERR_RECEIVE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_RECEIVE, __x) +#define DSI_DIRECT_CMD_RD_STS_ERR_OVERSIZE_SHIFT 5 +#define DSI_DIRECT_CMD_RD_STS_ERR_OVERSIZE_MASK 0x00000020 +#define DSI_DIRECT_CMD_RD_STS_ERR_OVERSIZE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_OVERSIZE, __x) +#define DSI_DIRECT_CMD_RD_STS_ERR_WRONG_LENGTH_SHIFT 6 +#define DSI_DIRECT_CMD_RD_STS_ERR_WRONG_LENGTH_MASK 0x00000040 +#define DSI_DIRECT_CMD_RD_STS_ERR_WRONG_LENGTH(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_WRONG_LENGTH, __x) +#define DSI_DIRECT_CMD_RD_STS_ERR_MISSING_EOT_SHIFT 7 +#define DSI_DIRECT_CMD_RD_STS_ERR_MISSING_EOT_MASK 0x00000080 +#define DSI_DIRECT_CMD_RD_STS_ERR_MISSING_EOT(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_MISSING_EOT, __x) +#define DSI_DIRECT_CMD_RD_STS_ERR_EOT_WITH_ERR_SHIFT 8 +#define DSI_DIRECT_CMD_RD_STS_ERR_EOT_WITH_ERR_MASK 0x00000100 +#define DSI_DIRECT_CMD_RD_STS_ERR_EOT_WITH_ERR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS, ERR_EOT_WITH_ERR, __x) +#define DSI_VID_MAIN_CTL 0x00000090 +#define DSI_VID_MAIN_CTL_START_MODE_SHIFT 0 +#define DSI_VID_MAIN_CTL_START_MODE_MASK 0x00000003 +#define DSI_VID_MAIN_CTL_START_MODE(__x) \ + DSI_VAL2REG(DSI_VID_MAIN_CTL, START_MODE, __x) +#define DSI_VID_MAIN_CTL_STOP_MODE_SHIFT 2 +#define DSI_VID_MAIN_CTL_STOP_MODE_MASK 0x0000000C +#define DSI_VID_MAIN_CTL_STOP_MODE(__x) \ + DSI_VAL2REG(DSI_VID_MAIN_CTL, STOP_MODE, __x) +#define DSI_VID_MAIN_CTL_VID_ID_SHIFT 4 +#define DSI_VID_MAIN_CTL_VID_ID_MASK 0x00000030 +#define DSI_VID_MAIN_CTL_VID_ID(__x) \ + DSI_VAL2REG(DSI_VID_MAIN_CTL, VID_ID, __x) +#define DSI_VID_MAIN_CTL_HEADER_SHIFT 6 +#define DSI_VID_MAIN_CTL_HEADER_MASK 0x00000FC0 +#define DSI_VID_MAIN_CTL_HEADER(__x) \ + DSI_VAL2REG(DSI_VID_MAIN_CTL, HEADER, __x) +#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_SHIFT 12 +#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_MASK 0x00003000 +#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_16BITS 0 +#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_18BITS 1 +#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_18BITS_LOOSE 2 +#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_24BITS 3 +#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE_ENUM(__x) \ + DSI_VAL2REG(DSI_VID_MAIN_CTL, VID_PIXEL_MODE, \ + DSI_VID_MAIN_CTL_VID_PIXEL_MODE_##__x) +#define DSI_VID_MAIN_CTL_VID_PIXEL_MODE(__x) \ + DSI_VAL2REG(DSI_VID_MAIN_CTL, VID_PIXEL_MODE, __x) +#define DSI_VID_MAIN_CTL_BURST_MODE_SHIFT 14 +#define DSI_VID_MAIN_CTL_BURST_MODE_MASK 0x00004000 +#define DSI_VID_MAIN_CTL_BURST_MODE(__x) \ + DSI_VAL2REG(DSI_VID_MAIN_CTL, BURST_MODE, __x) +#define DSI_VID_MAIN_CTL_SYNC_PULSE_ACTIVE_SHIFT 15 +#define DSI_VID_MAIN_CTL_SYNC_PULSE_ACTIVE_MASK 0x00008000 +#define DSI_VID_MAIN_CTL_SYNC_PULSE_ACTIVE(__x) \ + DSI_VAL2REG(DSI_VID_MAIN_CTL, SYNC_PULSE_ACTIVE, __x) +#define DSI_VID_MAIN_CTL_SYNC_PULSE_HORIZONTAL_SHIFT 16 +#define DSI_VID_MAIN_CTL_SYNC_PULSE_HORIZONTAL_MASK 0x00010000 +#define DSI_VID_MAIN_CTL_SYNC_PULSE_HORIZONTAL(__x) \ + DSI_VAL2REG(DSI_VID_MAIN_CTL, SYNC_PULSE_HORIZONTAL, __x) +#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_SHIFT 17 +#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_MASK 0x00060000 +#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_NULL 0 +#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_BLANKING 1 +#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_LP_0 2 +#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_LP_1 3 +#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_ENUM(__x) \ + DSI_VAL2REG(DSI_VID_MAIN_CTL, REG_BLKLINE_MODE, \ + DSI_VID_MAIN_CTL_REG_BLKLINE_MODE_##__x) +#define DSI_VID_MAIN_CTL_REG_BLKLINE_MODE(__x) \ + DSI_VAL2REG(DSI_VID_MAIN_CTL, REG_BLKLINE_MODE, __x) +#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_SHIFT 19 +#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_MASK 0x00180000 +#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_NULL 0 +#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_BLANKING 1 +#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_0 2 +#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_LP_1 3 +#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_ENUM(__x) \ + DSI_VAL2REG(DSI_VID_MAIN_CTL, REG_BLKEOL_MODE, \ + DSI_VID_MAIN_CTL_REG_BLKEOL_MODE_##__x) +#define DSI_VID_MAIN_CTL_REG_BLKEOL_MODE(__x) \ + DSI_VAL2REG(DSI_VID_MAIN_CTL, REG_BLKEOL_MODE, __x) +#define DSI_VID_MAIN_CTL_RECOVERY_MODE_SHIFT 21 +#define DSI_VID_MAIN_CTL_RECOVERY_MODE_MASK 0x00600000 +#define DSI_VID_MAIN_CTL_RECOVERY_MODE(__x) \ + DSI_VAL2REG(DSI_VID_MAIN_CTL, RECOVERY_MODE, __x) +#define DSI_VID_VSIZE 0x00000094 +#define DSI_VID_VSIZE_VSA_LENGTH_SHIFT 0 +#define DSI_VID_VSIZE_VSA_LENGTH_MASK 0x0000003F +#define DSI_VID_VSIZE_VSA_LENGTH(__x) \ + DSI_VAL2REG(DSI_VID_VSIZE, VSA_LENGTH, __x) +#define DSI_VID_VSIZE_VBP_LENGTH_SHIFT 6 +#define DSI_VID_VSIZE_VBP_LENGTH_MASK 0x00000FC0 +#define DSI_VID_VSIZE_VBP_LENGTH(__x) \ + DSI_VAL2REG(DSI_VID_VSIZE, VBP_LENGTH, __x) +#define DSI_VID_VSIZE_VFP_LENGTH_SHIFT 12 +#define DSI_VID_VSIZE_VFP_LENGTH_MASK 0x000FF000 +#define DSI_VID_VSIZE_VFP_LENGTH(__x) \ + DSI_VAL2REG(DSI_VID_VSIZE, VFP_LENGTH, __x) +#define DSI_VID_VSIZE_VACT_LENGTH_SHIFT 20 +#define DSI_VID_VSIZE_VACT_LENGTH_MASK 0x7FF00000 +#define DSI_VID_VSIZE_VACT_LENGTH(__x) \ + DSI_VAL2REG(DSI_VID_VSIZE, VACT_LENGTH, __x) +#define DSI_VID_HSIZE1 0x00000098 +#define DSI_VID_HSIZE1_HSA_LENGTH_SHIFT 0 +#define DSI_VID_HSIZE1_HSA_LENGTH_MASK 0x000003FF +#define DSI_VID_HSIZE1_HSA_LENGTH(__x) \ + DSI_VAL2REG(DSI_VID_HSIZE1, HSA_LENGTH, __x) +#define DSI_VID_HSIZE1_HBP_LENGTH_SHIFT 10 +#define DSI_VID_HSIZE1_HBP_LENGTH_MASK 0x000FFC00 +#define DSI_VID_HSIZE1_HBP_LENGTH(__x) \ + DSI_VAL2REG(DSI_VID_HSIZE1, HBP_LENGTH, __x) +#define DSI_VID_HSIZE1_HFP_LENGTH_SHIFT 20 +#define DSI_VID_HSIZE1_HFP_LENGTH_MASK 0x7FF00000 +#define DSI_VID_HSIZE1_HFP_LENGTH(__x) \ + DSI_VAL2REG(DSI_VID_HSIZE1, HFP_LENGTH, __x) +#define DSI_VID_HSIZE2 0x0000009C +#define DSI_VID_HSIZE2_RGB_SIZE_SHIFT 0 +#define DSI_VID_HSIZE2_RGB_SIZE_MASK 0x00001FFF +#define DSI_VID_HSIZE2_RGB_SIZE(__x) \ + DSI_VAL2REG(DSI_VID_HSIZE2, RGB_SIZE, __x) +#define DSI_VID_BLKSIZE1 0x000000A0 +#define DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_SHIFT 0 +#define DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK_MASK 0x00001FFF +#define DSI_VID_BLKSIZE1_BLKLINE_EVENT_PCK(__x) \ + DSI_VAL2REG(DSI_VID_BLKSIZE1, BLKLINE_EVENT_PCK, __x) +#define DSI_VID_BLKSIZE1_BLKEOL_PCK_SHIFT 13 +#define DSI_VID_BLKSIZE1_BLKEOL_PCK_MASK 0x03FFE000 +#define DSI_VID_BLKSIZE1_BLKEOL_PCK(__x) \ + DSI_VAL2REG(DSI_VID_BLKSIZE1, BLKEOL_PCK, __x) +#define DSI_VID_BLKSIZE2 0x000000A4 +#define DSI_VID_BLKSIZE2_BLKLINE_PULSE_PCK_SHIFT 0 +#define DSI_VID_BLKSIZE2_BLKLINE_PULSE_PCK_MASK 0x00001FFF +#define DSI_VID_BLKSIZE2_BLKLINE_PULSE_PCK(__x) \ + DSI_VAL2REG(DSI_VID_BLKSIZE2, BLKLINE_PULSE_PCK, __x) +#define DSI_VID_PCK_TIME 0x000000A8 +#define DSI_VID_PCK_TIME_BLKEOL_DURATION_SHIFT 0 +#define DSI_VID_PCK_TIME_BLKEOL_DURATION_MASK 0x00001FFF +#define DSI_VID_PCK_TIME_BLKEOL_DURATION(__x) \ + DSI_VAL2REG(DSI_VID_PCK_TIME, BLKEOL_DURATION, __x) +#define DSI_VID_DPHY_TIME 0x000000AC +#define DSI_VID_DPHY_TIME_REG_LINE_DURATION_SHIFT 0 +#define DSI_VID_DPHY_TIME_REG_LINE_DURATION_MASK 0x00001FFF +#define DSI_VID_DPHY_TIME_REG_LINE_DURATION(__x) \ + DSI_VAL2REG(DSI_VID_DPHY_TIME, REG_LINE_DURATION, __x) +#define DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_SHIFT 13 +#define DSI_VID_DPHY_TIME_REG_WAKEUP_TIME_MASK 0x00FFE000 +#define DSI_VID_DPHY_TIME_REG_WAKEUP_TIME(__x) \ + DSI_VAL2REG(DSI_VID_DPHY_TIME, REG_WAKEUP_TIME, __x) +#define DSI_VID_ERR_COLOR 0x000000B0 +#define DSI_VID_ERR_COLOR_COL_RED_SHIFT 0 +#define DSI_VID_ERR_COLOR_COL_RED_MASK 0x000000FF +#define DSI_VID_ERR_COLOR_COL_RED(__x) \ + DSI_VAL2REG(DSI_VID_ERR_COLOR, COL_RED, __x) +#define DSI_VID_ERR_COLOR_COL_GREEN_SHIFT 8 +#define DSI_VID_ERR_COLOR_COL_GREEN_MASK 0x0000FF00 +#define DSI_VID_ERR_COLOR_COL_GREEN(__x) \ + DSI_VAL2REG(DSI_VID_ERR_COLOR, COL_GREEN, __x) +#define DSI_VID_ERR_COLOR_COL_BLUE_SHIFT 16 +#define DSI_VID_ERR_COLOR_COL_BLUE_MASK 0x00FF0000 +#define DSI_VID_ERR_COLOR_COL_BLUE(__x) \ + DSI_VAL2REG(DSI_VID_ERR_COLOR, COL_BLUE, __x) +#define DSI_VID_ERR_COLOR_PAD_VAL_SHIFT 24 +#define DSI_VID_ERR_COLOR_PAD_VAL_MASK 0xFF000000 +#define DSI_VID_ERR_COLOR_PAD_VAL(__x) \ + DSI_VAL2REG(DSI_VID_ERR_COLOR, PAD_VAL, __x) +#define DSI_VID_VPOS 0x000000B4 +#define DSI_VID_VPOS_LINE_POS_SHIFT 0 +#define DSI_VID_VPOS_LINE_POS_MASK 0x00000003 +#define DSI_VID_VPOS_LINE_POS(__x) \ + DSI_VAL2REG(DSI_VID_VPOS, LINE_POS, __x) +#define DSI_VID_VPOS_LINE_VAL_SHIFT 2 +#define DSI_VID_VPOS_LINE_VAL_MASK 0x00001FFC +#define DSI_VID_VPOS_LINE_VAL(__x) \ + DSI_VAL2REG(DSI_VID_VPOS, LINE_VAL, __x) +#define DSI_VID_HPOS 0x000000B8 +#define DSI_VID_HPOS_HORIZONTAL_POS_SHIFT 0 +#define DSI_VID_HPOS_HORIZONTAL_POS_MASK 0x00000007 +#define DSI_VID_HPOS_HORIZONTAL_POS(__x) \ + DSI_VAL2REG(DSI_VID_HPOS, HORIZONTAL_POS, __x) +#define DSI_VID_HPOS_HORIZONTAL_VAL_SHIFT 3 +#define DSI_VID_HPOS_HORIZONTAL_VAL_MASK 0x0000FFF8 +#define DSI_VID_HPOS_HORIZONTAL_VAL(__x) \ + DSI_VAL2REG(DSI_VID_HPOS, HORIZONTAL_VAL, __x) +#define DSI_VID_MODE_STS 0x000000BC +#define DSI_VID_MODE_STS_VSG_RUNNING_SHIFT 0 +#define DSI_VID_MODE_STS_VSG_RUNNING_MASK 0x00000001 +#define DSI_VID_MODE_STS_VSG_RUNNING(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS, VSG_RUNNING, __x) +#define DSI_VID_MODE_STS_ERR_MISSING_DATA_SHIFT 1 +#define DSI_VID_MODE_STS_ERR_MISSING_DATA_MASK 0x00000002 +#define DSI_VID_MODE_STS_ERR_MISSING_DATA(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS, ERR_MISSING_DATA, __x) +#define DSI_VID_MODE_STS_ERR_MISSING_HSYNC_SHIFT 2 +#define DSI_VID_MODE_STS_ERR_MISSING_HSYNC_MASK 0x00000004 +#define DSI_VID_MODE_STS_ERR_MISSING_HSYNC(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS, ERR_MISSING_HSYNC, __x) +#define DSI_VID_MODE_STS_ERR_MISSING_VSYNC_SHIFT 3 +#define DSI_VID_MODE_STS_ERR_MISSING_VSYNC_MASK 0x00000008 +#define DSI_VID_MODE_STS_ERR_MISSING_VSYNC(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS, ERR_MISSING_VSYNC, __x) +#define DSI_VID_MODE_STS_REG_ERR_SMALL_LENGTH_SHIFT 4 +#define DSI_VID_MODE_STS_REG_ERR_SMALL_LENGTH_MASK 0x00000010 +#define DSI_VID_MODE_STS_REG_ERR_SMALL_LENGTH(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS, REG_ERR_SMALL_LENGTH, __x) +#define DSI_VID_MODE_STS_REG_ERR_SMALL_HEIGHT_SHIFT 5 +#define DSI_VID_MODE_STS_REG_ERR_SMALL_HEIGHT_MASK 0x00000020 +#define DSI_VID_MODE_STS_REG_ERR_SMALL_HEIGHT(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS, REG_ERR_SMALL_HEIGHT, __x) +#define DSI_VID_MODE_STS_ERR_BURSTWRITE_SHIFT 6 +#define DSI_VID_MODE_STS_ERR_BURSTWRITE_MASK 0x00000040 +#define DSI_VID_MODE_STS_ERR_BURSTWRITE(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS, ERR_BURSTWRITE, __x) +#define DSI_VID_MODE_STS_ERR_LONGWRITE_SHIFT 7 +#define DSI_VID_MODE_STS_ERR_LONGWRITE_MASK 0x00000080 +#define DSI_VID_MODE_STS_ERR_LONGWRITE(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS, ERR_LONGWRITE, __x) +#define DSI_VID_MODE_STS_ERR_LONGREAD_SHIFT 8 +#define DSI_VID_MODE_STS_ERR_LONGREAD_MASK 0x00000100 +#define DSI_VID_MODE_STS_ERR_LONGREAD(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS, ERR_LONGREAD, __x) +#define DSI_VID_MODE_STS_ERR_VRS_WRONG_LENGTH_SHIFT 9 +#define DSI_VID_MODE_STS_ERR_VRS_WRONG_LENGTH_MASK 0x00000200 +#define DSI_VID_MODE_STS_ERR_VRS_WRONG_LENGTH(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS, ERR_VRS_WRONG_LENGTH, __x) +#define DSI_VID_MODE_STS_VSG_RECOVERY_SHIFT 10 +#define DSI_VID_MODE_STS_VSG_RECOVERY_MASK 0x00000400 +#define DSI_VID_MODE_STS_VSG_RECOVERY(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS, VSG_RECOVERY, __x) +#define DSI_VID_VCA_SETTING1 0x000000C0 +#define DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_SHIFT 0 +#define DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT_MASK 0x0000FFFF +#define DSI_VID_VCA_SETTING1_MAX_BURST_LIMIT(__x) \ + DSI_VAL2REG(DSI_VID_VCA_SETTING1, MAX_BURST_LIMIT, __x) +#define DSI_VID_VCA_SETTING1_BURST_LP_SHIFT 16 +#define DSI_VID_VCA_SETTING1_BURST_LP_MASK 0x00010000 +#define DSI_VID_VCA_SETTING1_BURST_LP(__x) \ + DSI_VAL2REG(DSI_VID_VCA_SETTING1, BURST_LP, __x) +#define DSI_VID_VCA_SETTING2 0x000000C4 +#define DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_SHIFT 0 +#define DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT_MASK 0x0000FFFF +#define DSI_VID_VCA_SETTING2_EXACT_BURST_LIMIT(__x) \ + DSI_VAL2REG(DSI_VID_VCA_SETTING2, EXACT_BURST_LIMIT, __x) +#define DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT_SHIFT 16 +#define DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT_MASK 0xFFFF0000 +#define DSI_VID_VCA_SETTING2_MAX_LINE_LIMIT(__x) \ + DSI_VAL2REG(DSI_VID_VCA_SETTING2, MAX_LINE_LIMIT, __x) +#define DSI_TVG_CTL 0x000000C8 +#define DSI_TVG_CTL_TVG_RUN_SHIFT 0 +#define DSI_TVG_CTL_TVG_RUN_MASK 0x00000001 +#define DSI_TVG_CTL_TVG_RUN(__x) \ + DSI_VAL2REG(DSI_TVG_CTL, TVG_RUN, __x) +#define DSI_TVG_CTL_TVG_STOPMODE_SHIFT 1 +#define DSI_TVG_CTL_TVG_STOPMODE_MASK 0x00000006 +#define DSI_TVG_CTL_TVG_STOPMODE(__x) \ + DSI_VAL2REG(DSI_TVG_CTL, TVG_STOPMODE, __x) +#define DSI_TVG_CTL_TVG_MODE_SHIFT 3 +#define DSI_TVG_CTL_TVG_MODE_MASK 0x00000018 +#define DSI_TVG_CTL_TVG_MODE(__x) \ + DSI_VAL2REG(DSI_TVG_CTL, TVG_MODE, __x) +#define DSI_TVG_CTL_TVG_STRIPE_SIZE_SHIFT 5 +#define DSI_TVG_CTL_TVG_STRIPE_SIZE_MASK 0x000000E0 +#define DSI_TVG_CTL_TVG_STRIPE_SIZE(__x) \ + DSI_VAL2REG(DSI_TVG_CTL, TVG_STRIPE_SIZE, __x) +#define DSI_TVG_IMG_SIZE 0x000000CC +#define DSI_TVG_IMG_SIZE_TVG_LINE_SIZE_SHIFT 0 +#define DSI_TVG_IMG_SIZE_TVG_LINE_SIZE_MASK 0x00001FFF +#define DSI_TVG_IMG_SIZE_TVG_LINE_SIZE(__x) \ + DSI_VAL2REG(DSI_TVG_IMG_SIZE, TVG_LINE_SIZE, __x) +#define DSI_TVG_IMG_SIZE_TVG_NBLINE_SHIFT 16 +#define DSI_TVG_IMG_SIZE_TVG_NBLINE_MASK 0x07FF0000 +#define DSI_TVG_IMG_SIZE_TVG_NBLINE(__x) \ + DSI_VAL2REG(DSI_TVG_IMG_SIZE, TVG_NBLINE, __x) +#define DSI_TVG_COLOR1 0x000000D0 +#define DSI_TVG_COLOR1_COL1_RED_SHIFT 0 +#define DSI_TVG_COLOR1_COL1_RED_MASK 0x000000FF +#define DSI_TVG_COLOR1_COL1_RED(__x) \ + DSI_VAL2REG(DSI_TVG_COLOR1, COL1_RED, __x) +#define DSI_TVG_COLOR1_COL1_GREEN_SHIFT 8 +#define DSI_TVG_COLOR1_COL1_GREEN_MASK 0x0000FF00 +#define DSI_TVG_COLOR1_COL1_GREEN(__x) \ + DSI_VAL2REG(DSI_TVG_COLOR1, COL1_GREEN, __x) +#define DSI_TVG_COLOR1_COL1_BLUE_SHIFT 16 +#define DSI_TVG_COLOR1_COL1_BLUE_MASK 0x00FF0000 +#define DSI_TVG_COLOR1_COL1_BLUE(__x) \ + DSI_VAL2REG(DSI_TVG_COLOR1, COL1_BLUE, __x) +#define DSI_TVG_COLOR2 0x000000D4 +#define DSI_TVG_COLOR2_COL2_RED_SHIFT 0 +#define DSI_TVG_COLOR2_COL2_RED_MASK 0x000000FF +#define DSI_TVG_COLOR2_COL2_RED(__x) \ + DSI_VAL2REG(DSI_TVG_COLOR2, COL2_RED, __x) +#define DSI_TVG_COLOR2_COL2_GREEN_SHIFT 8 +#define DSI_TVG_COLOR2_COL2_GREEN_MASK 0x0000FF00 +#define DSI_TVG_COLOR2_COL2_GREEN(__x) \ + DSI_VAL2REG(DSI_TVG_COLOR2, COL2_GREEN, __x) +#define DSI_TVG_COLOR2_COL2_BLUE_SHIFT 16 +#define DSI_TVG_COLOR2_COL2_BLUE_MASK 0x00FF0000 +#define DSI_TVG_COLOR2_COL2_BLUE(__x) \ + DSI_VAL2REG(DSI_TVG_COLOR2, COL2_BLUE, __x) +#define DSI_TVG_STS 0x000000D8 +#define DSI_TVG_STS_TVG_RUNNING_SHIFT 0 +#define DSI_TVG_STS_TVG_RUNNING_MASK 0x00000001 +#define DSI_TVG_STS_TVG_RUNNING(__x) \ + DSI_VAL2REG(DSI_TVG_STS, TVG_RUNNING, __x) +#define DSI_TBG_CTL 0x000000E0 +#define DSI_TBG_CTL_TBG_START_SHIFT 0 +#define DSI_TBG_CTL_TBG_START_MASK 0x00000001 +#define DSI_TBG_CTL_TBG_START(__x) \ + DSI_VAL2REG(DSI_TBG_CTL, TBG_START, __x) +#define DSI_TBG_CTL_TBG_HS_REQ_SHIFT 1 +#define DSI_TBG_CTL_TBG_HS_REQ_MASK 0x00000002 +#define DSI_TBG_CTL_TBG_HS_REQ(__x) \ + DSI_VAL2REG(DSI_TBG_CTL, TBG_HS_REQ, __x) +#define DSI_TBG_CTL_TBG_DATA_SEL_SHIFT 2 +#define DSI_TBG_CTL_TBG_DATA_SEL_MASK 0x00000004 +#define DSI_TBG_CTL_TBG_DATA_SEL(__x) \ + DSI_VAL2REG(DSI_TBG_CTL, TBG_DATA_SEL, __x) +#define DSI_TBG_CTL_TBG_MODE_SHIFT 3 +#define DSI_TBG_CTL_TBG_MODE_MASK 0x00000018 +#define DSI_TBG_CTL_TBG_MODE_1BYTE 0 +#define DSI_TBG_CTL_TBG_MODE_2BYTE 1 +#define DSI_TBG_CTL_TBG_MODE_BURST_COUNTER 2 +#define DSI_TBG_CTL_TBG_MODE_BURST 3 +#define DSI_TBG_CTL_TBG_MODE_ENUM(__x) \ + DSI_VAL2REG(DSI_TBG_CTL, TBG_MODE, DSI_TBG_CTL_TBG_MODE_##__x) +#define DSI_TBG_CTL_TBG_MODE(__x) \ + DSI_VAL2REG(DSI_TBG_CTL, TBG_MODE, __x) +#define DSI_TBG_SETTING 0x000000E4 +#define DSI_TBG_SETTING_TBG_DATA_SHIFT 0 +#define DSI_TBG_SETTING_TBG_DATA_MASK 0x0000FFFF +#define DSI_TBG_SETTING_TBG_DATA(__x) \ + DSI_VAL2REG(DSI_TBG_SETTING, TBG_DATA, __x) +#define DSI_TBG_SETTING_TBG_CPT_SHIFT 16 +#define DSI_TBG_SETTING_TBG_CPT_MASK 0x0FFF0000 +#define DSI_TBG_SETTING_TBG_CPT(__x) \ + DSI_VAL2REG(DSI_TBG_SETTING, TBG_CPT, __x) +#define DSI_TBG_STS 0x000000E8 +#define DSI_TBG_STS_TBG_STATUS_SHIFT 0 +#define DSI_TBG_STS_TBG_STATUS_MASK 0x00000001 +#define DSI_TBG_STS_TBG_STATUS(__x) \ + DSI_VAL2REG(DSI_TBG_STS, TBG_STATUS, __x) +#define DSI_MCTL_MAIN_STS_CTL 0x000000F0 +#define DSI_MCTL_MAIN_STS_CTL_PLL_LOCK_EN_SHIFT 0 +#define DSI_MCTL_MAIN_STS_CTL_PLL_LOCK_EN_MASK 0x00000001 +#define DSI_MCTL_MAIN_STS_CTL_PLL_LOCK_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, PLL_LOCK_EN, __x) +#define DSI_MCTL_MAIN_STS_CTL_CLKLANE_READY_EN_SHIFT 1 +#define DSI_MCTL_MAIN_STS_CTL_CLKLANE_READY_EN_MASK 0x00000002 +#define DSI_MCTL_MAIN_STS_CTL_CLKLANE_READY_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, CLKLANE_READY_EN, __x) +#define DSI_MCTL_MAIN_STS_CTL_DAT1_READY_EN_SHIFT 2 +#define DSI_MCTL_MAIN_STS_CTL_DAT1_READY_EN_MASK 0x00000004 +#define DSI_MCTL_MAIN_STS_CTL_DAT1_READY_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, DAT1_READY_EN, __x) +#define DSI_MCTL_MAIN_STS_CTL_DAT2_READY_EN_SHIFT 3 +#define DSI_MCTL_MAIN_STS_CTL_DAT2_READY_EN_MASK 0x00000008 +#define DSI_MCTL_MAIN_STS_CTL_DAT2_READY_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, DAT2_READY_EN, __x) +#define DSI_MCTL_MAIN_STS_CTL_HSTX_TO_ERR_EN_SHIFT 4 +#define DSI_MCTL_MAIN_STS_CTL_HSTX_TO_ERR_EN_MASK 0x00000010 +#define DSI_MCTL_MAIN_STS_CTL_HSTX_TO_ERR_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, HSTX_TO_ERR_EN, __x) +#define DSI_MCTL_MAIN_STS_CTL_LPRX_TO_ERR_EN_SHIFT 5 +#define DSI_MCTL_MAIN_STS_CTL_LPRX_TO_ERR_EN_MASK 0x00000020 +#define DSI_MCTL_MAIN_STS_CTL_LPRX_TO_ERR_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, LPRX_TO_ERR_EN, __x) +#define DSI_MCTL_MAIN_STS_CTL_CRS_UNTERM_PCK_ERR_EN_SHIFT 6 +#define DSI_MCTL_MAIN_STS_CTL_CRS_UNTERM_PCK_ERR_EN_MASK 0x00000040 +#define DSI_MCTL_MAIN_STS_CTL_CRS_UNTERM_PCK_ERR_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, CRS_UNTERM_PCK_ERR_EN, __x) +#define DSI_MCTL_MAIN_STS_CTL_VRS_UNTERM_PCK_ERR_EN_SHIFT 7 +#define DSI_MCTL_MAIN_STS_CTL_VRS_UNTERM_PCK_ERR_EN_MASK 0x00000080 +#define DSI_MCTL_MAIN_STS_CTL_VRS_UNTERM_PCK_ERR_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, VRS_UNTERM_PCK_ERR_EN, __x) +#define DSI_MCTL_MAIN_STS_CTL_PLL_LOCK_EDGE_SHIFT 16 +#define DSI_MCTL_MAIN_STS_CTL_PLL_LOCK_EDGE_MASK 0x00010000 +#define DSI_MCTL_MAIN_STS_CTL_PLL_LOCK_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, PLL_LOCK_EDGE, __x) +#define DSI_MCTL_MAIN_STS_CTL_CLKLANE_READY_EDGE_SHIFT 17 +#define DSI_MCTL_MAIN_STS_CTL_CLKLANE_READY_EDGE_MASK 0x00020000 +#define DSI_MCTL_MAIN_STS_CTL_CLKLANE_READY_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, CLKLANE_READY_EDGE, __x) +#define DSI_MCTL_MAIN_STS_CTL_DAT1_READY_EDGE_SHIFT 18 +#define DSI_MCTL_MAIN_STS_CTL_DAT1_READY_EDGE_MASK 0x00040000 +#define DSI_MCTL_MAIN_STS_CTL_DAT1_READY_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, DAT1_READY_EDGE, __x) +#define DSI_MCTL_MAIN_STS_CTL_DAT2_READY_EDGE_SHIFT 19 +#define DSI_MCTL_MAIN_STS_CTL_DAT2_READY_EDGE_MASK 0x00080000 +#define DSI_MCTL_MAIN_STS_CTL_DAT2_READY_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, DAT2_READY_EDGE, __x) +#define DSI_MCTL_MAIN_STS_CTL_HSTX_TO_ERR_EDGE_SHIFT 20 +#define DSI_MCTL_MAIN_STS_CTL_HSTX_TO_ERR_EDGE_MASK 0x00100000 +#define DSI_MCTL_MAIN_STS_CTL_HSTX_TO_ERR_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, HSTX_TO_ERR_EDGE, __x) +#define DSI_MCTL_MAIN_STS_CTL_LPRX_TO_ERR_EDGE_SHIFT 21 +#define DSI_MCTL_MAIN_STS_CTL_LPRX_TO_ERR_EDGE_MASK 0x00200000 +#define DSI_MCTL_MAIN_STS_CTL_LPRX_TO_ERR_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, LPRX_TO_ERR_EDGE, __x) +#define DSI_MCTL_MAIN_STS_CTL_CRS_UNTERM_PCK_ERR_EDGE_SHIFT 22 +#define DSI_MCTL_MAIN_STS_CTL_CRS_UNTERM_PCK_ERR_EDGE_MASK 0x00400000 +#define DSI_MCTL_MAIN_STS_CTL_CRS_UNTERM_PCK_ERR_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, CRS_UNTERM_PCK_ERR_EDGE, __x) +#define DSI_MCTL_MAIN_STS_CTL_VRS_UNTERM_PCK_ERR_EDGE_SHIFT 23 +#define DSI_MCTL_MAIN_STS_CTL_VRS_UNTERM_PCK_ERR_EDGE_MASK 0x00800000 +#define DSI_MCTL_MAIN_STS_CTL_VRS_UNTERM_PCK_ERR_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CTL, VRS_UNTERM_PCK_ERR_EDGE, __x) +#define DSI_CMD_MODE_STS_CTL 0x000000F4 +#define DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EN_SHIFT 0 +#define DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EN_MASK 0x00000001 +#define DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EN(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_NO_TE_EN, __x) +#define DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EN_SHIFT 1 +#define DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EN_MASK 0x00000002 +#define DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EN(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_TE_MISS_EN, __x) +#define DSI_CMD_MODE_STS_CTL_ERR_SDI1_UNDERRUN_EN_SHIFT 2 +#define DSI_CMD_MODE_STS_CTL_ERR_SDI1_UNDERRUN_EN_MASK 0x00000004 +#define DSI_CMD_MODE_STS_CTL_ERR_SDI1_UNDERRUN_EN(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_SDI1_UNDERRUN_EN, __x) +#define DSI_CMD_MODE_STS_CTL_ERR_SDI2_UNDERRUN_EN_SHIFT 3 +#define DSI_CMD_MODE_STS_CTL_ERR_SDI2_UNDERRUN_EN_MASK 0x00000008 +#define DSI_CMD_MODE_STS_CTL_ERR_SDI2_UNDERRUN_EN(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_SDI2_UNDERRUN_EN, __x) +#define DSI_CMD_MODE_STS_CTL_ERR_UNWANTED_RD_EN_SHIFT 4 +#define DSI_CMD_MODE_STS_CTL_ERR_UNWANTED_RD_EN_MASK 0x00000010 +#define DSI_CMD_MODE_STS_CTL_ERR_UNWANTED_RD_EN(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_UNWANTED_RD_EN, __x) +#define DSI_CMD_MODE_STS_CTL_CSM_RUNNING_EN_SHIFT 5 +#define DSI_CMD_MODE_STS_CTL_CSM_RUNNING_EN_MASK 0x00000020 +#define DSI_CMD_MODE_STS_CTL_CSM_RUNNING_EN(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, CSM_RUNNING_EN, __x) +#define DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EDGE_SHIFT 16 +#define DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EDGE_MASK 0x00010000 +#define DSI_CMD_MODE_STS_CTL_ERR_NO_TE_EDGE(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_NO_TE_EDGE, __x) +#define DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EDGE_SHIFT 17 +#define DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EDGE_MASK 0x00020000 +#define DSI_CMD_MODE_STS_CTL_ERR_TE_MISS_EDGE(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_TE_MISS_EDGE, __x) +#define DSI_CMD_MODE_STS_CTL_ERR_SDI1_UNDERRUN_EDGE_SHIFT 18 +#define DSI_CMD_MODE_STS_CTL_ERR_SDI1_UNDERRUN_EDGE_MASK 0x00040000 +#define DSI_CMD_MODE_STS_CTL_ERR_SDI1_UNDERRUN_EDGE(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_SDI1_UNDERRUN_EDGE, __x) +#define DSI_CMD_MODE_STS_CTL_ERR_SDI2_UNDERRUN_EDGE_SHIFT 19 +#define DSI_CMD_MODE_STS_CTL_ERR_SDI2_UNDERRUN_EDGE_MASK 0x00080000 +#define DSI_CMD_MODE_STS_CTL_ERR_SDI2_UNDERRUN_EDGE(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_SDI2_UNDERRUN_EDGE, __x) +#define DSI_CMD_MODE_STS_CTL_ERR_UNWANTED_RD_EDGE_SHIFT 20 +#define DSI_CMD_MODE_STS_CTL_ERR_UNWANTED_RD_EDGE_MASK 0x00100000 +#define DSI_CMD_MODE_STS_CTL_ERR_UNWANTED_RD_EDGE(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, ERR_UNWANTED_RD_EDGE, __x) +#define DSI_CMD_MODE_STS_CTL_CSM_RUNNING_EDGE_SHIFT 21 +#define DSI_CMD_MODE_STS_CTL_CSM_RUNNING_EDGE_MASK 0x00200000 +#define DSI_CMD_MODE_STS_CTL_CSM_RUNNING_EDGE(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CTL, CSM_RUNNING_EDGE, __x) +#define DSI_DIRECT_CMD_STS_CTL 0x000000F8 +#define DSI_DIRECT_CMD_STS_CTL_CMD_TRANSMISSION_EN_SHIFT 0 +#define DSI_DIRECT_CMD_STS_CTL_CMD_TRANSMISSION_EN_MASK 0x00000001 +#define DSI_DIRECT_CMD_STS_CTL_CMD_TRANSMISSION_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, CMD_TRANSMISSION_EN, __x) +#define DSI_DIRECT_CMD_STS_CTL_WRITE_COMPLETED_EN_SHIFT 1 +#define DSI_DIRECT_CMD_STS_CTL_WRITE_COMPLETED_EN_MASK 0x00000002 +#define DSI_DIRECT_CMD_STS_CTL_WRITE_COMPLETED_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, WRITE_COMPLETED_EN, __x) +#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_COMPLETED_EN_SHIFT 2 +#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_COMPLETED_EN_MASK 0x00000004 +#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_COMPLETED_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, TRIGGER_COMPLETED_EN, __x) +#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_EN_SHIFT 3 +#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_EN_MASK 0x00000008 +#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, READ_COMPLETED_EN, __x) +#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_RECEIVED_EN_SHIFT 4 +#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_RECEIVED_EN_MASK 0x00000010 +#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_RECEIVED_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, ACKNOWLEDGE_RECEIVED_EN, __x) +#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EN_SHIFT 5 +#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EN_MASK 0x00000020 +#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, ACKNOWLEDGE_WITH_ERR_EN, __x) +#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_RECEIVED_EN_SHIFT 6 +#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_RECEIVED_EN_MASK 0x00000040 +#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_RECEIVED_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, TRIGGER_RECEIVED_EN, __x) +#define DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EN_SHIFT 7 +#define DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EN_MASK 0x00000080 +#define DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, TE_RECEIVED_EN, __x) +#define DSI_DIRECT_CMD_STS_CTL_BTA_COMPLETED_EN_SHIFT 8 +#define DSI_DIRECT_CMD_STS_CTL_BTA_COMPLETED_EN_MASK 0x00000100 +#define DSI_DIRECT_CMD_STS_CTL_BTA_COMPLETED_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, BTA_COMPLETED_EN, __x) +#define DSI_DIRECT_CMD_STS_CTL_BTA_FINISHED_EN_SHIFT 9 +#define DSI_DIRECT_CMD_STS_CTL_BTA_FINISHED_EN_MASK 0x00000200 +#define DSI_DIRECT_CMD_STS_CTL_BTA_FINISHED_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, BTA_FINISHED_EN, __x) +#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_WITH_ERR_EN_SHIFT 10 +#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_WITH_ERR_EN_MASK 0x00000400 +#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_WITH_ERR_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, READ_COMPLETED_WITH_ERR_EN, __x) +#define DSI_DIRECT_CMD_STS_CTL_CMD_TRANSMISSION_EDGE_SHIFT 16 +#define DSI_DIRECT_CMD_STS_CTL_CMD_TRANSMISSION_EDGE_MASK 0x00010000 +#define DSI_DIRECT_CMD_STS_CTL_CMD_TRANSMISSION_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, CMD_TRANSMISSION_EDGE, __x) +#define DSI_DIRECT_CMD_STS_CTL_WRITE_COMPLETED_EDGE_SHIFT 17 +#define DSI_DIRECT_CMD_STS_CTL_WRITE_COMPLETED_EDGE_MASK 0x00020000 +#define DSI_DIRECT_CMD_STS_CTL_WRITE_COMPLETED_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, WRITE_COMPLETED_EDGE, __x) +#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_COMPLETED_EDGE_SHIFT 18 +#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_COMPLETED_EDGE_MASK 0x00040000 +#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_COMPLETED_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, TRIGGER_COMPLETED_EDGE, __x) +#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_EDGE_SHIFT 19 +#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_EDGE_MASK 0x00080000 +#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, READ_COMPLETED_EDGE, __x) +#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_RECEIVED_EDGE_SHIFT 20 +#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_RECEIVED_EDGE_MASK 0x00100000 +#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_RECEIVED_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, ACKNOWLEDGE_RECEIVED_EDGE, __x) +#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EDGE_SHIFT 21 +#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EDGE_MASK 0x00200000 +#define DSI_DIRECT_CMD_STS_CTL_ACKNOWLEDGE_WITH_ERR_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, ACKNOWLEDGE_WITH_ERR_EDGE, __x) +#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_RECEIVED_EDGE_SHIFT 22 +#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_RECEIVED_EDGE_MASK 0x00400000 +#define DSI_DIRECT_CMD_STS_CTL_TRIGGER_RECEIVED_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, TRIGGER_RECEIVED_EDGE, __x) +#define DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EDGE_SHIFT 23 +#define DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EDGE_MASK 0x00800000 +#define DSI_DIRECT_CMD_STS_CTL_TE_RECEIVED_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, TE_RECEIVED_EDGE, __x) +#define DSI_DIRECT_CMD_STS_CTL_BTA_COMPLETED_EDGE_SHIFT 24 +#define DSI_DIRECT_CMD_STS_CTL_BTA_COMPLETED_EDGE_MASK 0x01000000 +#define DSI_DIRECT_CMD_STS_CTL_BTA_COMPLETED_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, BTA_COMPLETED_EDGE, __x) +#define DSI_DIRECT_CMD_STS_CTL_BTA_FINISHED_EDGE_SHIFT 25 +#define DSI_DIRECT_CMD_STS_CTL_BTA_FINISHED_EDGE_MASK 0x02000000 +#define DSI_DIRECT_CMD_STS_CTL_BTA_FINISHED_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, BTA_FINISHED_EDGE, __x) +#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_WITH_ERR_EDGE_SHIFT 26 +#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_WITH_ERR_EDGE_MASK 0x04000000 +#define DSI_DIRECT_CMD_STS_CTL_READ_COMPLETED_WITH_ERR_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CTL, READ_COMPLETED_WITH_ERR_EDGE, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL 0x000000FC +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_FIXED_EN_SHIFT 0 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_FIXED_EN_MASK 0x00000001 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_FIXED_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_FIXED_EN, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNCORRECTABLE_EN_SHIFT 1 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNCORRECTABLE_EN_MASK 0x00000002 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNCORRECTABLE_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_UNCORRECTABLE_EN, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_CHECKSUM_EN_SHIFT 2 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_CHECKSUM_EN_MASK 0x00000004 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_CHECKSUM_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_CHECKSUM_EN, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNDECODABLE_EN_SHIFT 3 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNDECODABLE_EN_MASK 0x00000008 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNDECODABLE_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_UNDECODABLE_EN, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_RECEIVE_EN_SHIFT 4 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_RECEIVE_EN_MASK 0x00000010 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_RECEIVE_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_RECEIVE_EN, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_OVERSIZE_EN_SHIFT 5 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_OVERSIZE_EN_MASK 0x00000020 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_OVERSIZE_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_OVERSIZE_EN, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_WRONG_LENGTH_EN_SHIFT 6 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_WRONG_LENGTH_EN_MASK 0x00000040 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_WRONG_LENGTH_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_WRONG_LENGTH_EN, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_MISSING_EOT_EN_SHIFT 7 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_MISSING_EOT_EN_MASK 0x00000080 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_MISSING_EOT_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_MISSING_EOT_EN, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_EOT_WITH_ERR_EN_SHIFT 8 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_EOT_WITH_ERR_EN_MASK 0x00000100 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_EOT_WITH_ERR_EN(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_EOT_WITH_ERR_EN, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_FIXED_EDGE_SHIFT 16 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_FIXED_EDGE_MASK 0x00010000 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_FIXED_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_FIXED_EDGE, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNCORRECTABLE_EDGE_SHIFT 17 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNCORRECTABLE_EDGE_MASK 0x00020000 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNCORRECTABLE_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_UNCORRECTABLE_EDGE, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_CHECKSUM_EDGE_SHIFT 18 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_CHECKSUM_EDGE_MASK 0x00040000 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_CHECKSUM_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_CHECKSUM_EDGE, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNDECODABLE_EDGE_SHIFT 19 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNDECODABLE_EDGE_MASK 0x00080000 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_UNDECODABLE_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_UNDECODABLE_EDGE, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_RECEIVE_EDGE_SHIFT 20 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_RECEIVE_EDGE_MASK 0x00100000 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_RECEIVE_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_RECEIVE_EDGE, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_OVERSIZE_EDGE_SHIFT 21 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_OVERSIZE_EDGE_MASK 0x00200000 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_OVERSIZE_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_OVERSIZE_EDGE, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_WRONG_LENGTH_EDGE_SHIFT 22 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_WRONG_LENGTH_EDGE_MASK 0x00400000 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_WRONG_LENGTH_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_WRONG_LENGTH_EDGE, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_MISSING_EOT_EDGE_SHIFT 23 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_MISSING_EOT_EDGE_MASK 0x00800000 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_MISSING_EOT_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_MISSING_EOT_EDGE, __x) +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_EOT_WITH_ERR_EDGE_SHIFT 24 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_EOT_WITH_ERR_EDGE_MASK 0x01000000 +#define DSI_DIRECT_CMD_RD_STS_CTL_ERR_EOT_WITH_ERR_EDGE(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CTL, ERR_EOT_WITH_ERR_EDGE, __x) +#define DSI_VID_MODE_STS_CTL 0x00000100 +#define DSI_VID_MODE_STS_CTL_VSG_RUNNING_EN_SHIFT 0 +#define DSI_VID_MODE_STS_CTL_VSG_RUNNING_EN_MASK 0x00000001 +#define DSI_VID_MODE_STS_CTL_VSG_RUNNING_EN(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, VSG_RUNNING_EN, __x) +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA_EN_SHIFT 1 +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA_EN_MASK 0x00000002 +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA_EN(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_MISSING_DATA_EN, __x) +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_HSYNC_EN_SHIFT 2 +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_HSYNC_EN_MASK 0x00000004 +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_HSYNC_EN(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_MISSING_HSYNC_EN, __x) +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC_EN_SHIFT 3 +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC_EN_MASK 0x00000008 +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC_EN(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_MISSING_VSYNC_EN, __x) +#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_LENGTH_EN_SHIFT 4 +#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_LENGTH_EN_MASK 0x00000010 +#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_LENGTH_EN(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, REG_ERR_SMALL_LENGTH_EN, __x) +#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_HEIGHT_EN_SHIFT 5 +#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_HEIGHT_EN_MASK 0x00000020 +#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_HEIGHT_EN(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, REG_ERR_SMALL_HEIGHT_EN, __x) +#define DSI_VID_MODE_STS_CTL_ERR_BURSTWRITE_EN_SHIFT 6 +#define DSI_VID_MODE_STS_CTL_ERR_BURSTWRITE_EN_MASK 0x00000040 +#define DSI_VID_MODE_STS_CTL_ERR_BURSTWRITE_EN(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_BURSTWRITE_EN, __x) +#define DSI_VID_MODE_STS_CTL_ERR_LONGWRITE_EN_SHIFT 7 +#define DSI_VID_MODE_STS_CTL_ERR_LONGWRITE_EN_MASK 0x00000080 +#define DSI_VID_MODE_STS_CTL_ERR_LONGWRITE_EN(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_LONGWRITE_EN, __x) +#define DSI_VID_MODE_STS_CTL_ERR_LONGREAD_EN_SHIFT 8 +#define DSI_VID_MODE_STS_CTL_ERR_LONGREAD_EN_MASK 0x00000100 +#define DSI_VID_MODE_STS_CTL_ERR_LONGREAD_EN(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_LONGREAD_EN, __x) +#define DSI_VID_MODE_STS_CTL_ERR_VRS_WRONG_LENGTH_EN_SHIFT 9 +#define DSI_VID_MODE_STS_CTL_ERR_VRS_WRONG_LENGTH_EN_MASK 0x00000200 +#define DSI_VID_MODE_STS_CTL_ERR_VRS_WRONG_LENGTH_EN(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_VRS_WRONG_LENGTH_EN, __x) +#define DSI_VID_MODE_STS_CTL_VSG_RUNNING_EDGE_SHIFT 16 +#define DSI_VID_MODE_STS_CTL_VSG_RUNNING_EDGE_MASK 0x00010000 +#define DSI_VID_MODE_STS_CTL_VSG_RUNNING_EDGE(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, VSG_RUNNING_EDGE, __x) +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA_EDGE_SHIFT 17 +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA_EDGE_MASK 0x00020000 +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_DATA_EDGE(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_MISSING_DATA_EDGE, __x) +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_HSYNC_EDGE_SHIFT 18 +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_HSYNC_EDGE_MASK 0x00040000 +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_HSYNC_EDGE(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_MISSING_HSYNC_EDGE, __x) +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC_EDGE_SHIFT 19 +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC_EDGE_MASK 0x00080000 +#define DSI_VID_MODE_STS_CTL_ERR_MISSING_VSYNC_EDGE(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_MISSING_VSYNC_EDGE, __x) +#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_LENGTH_EDGE_SHIFT 20 +#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_LENGTH_EDGE_MASK 0x00100000 +#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_LENGTH_EDGE(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, REG_ERR_SMALL_LENGTH_EDGE, __x) +#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_HEIGHT_EDGE_SHIFT 21 +#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_HEIGHT_EDGE_MASK 0x00200000 +#define DSI_VID_MODE_STS_CTL_REG_ERR_SMALL_HEIGHT_EDGE(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, REG_ERR_SMALL_HEIGHT_EDGE, __x) +#define DSI_VID_MODE_STS_CTL_ERR_BURSTWRITE_EDGE_SHIFT 22 +#define DSI_VID_MODE_STS_CTL_ERR_BURSTWRITE_EDGE_MASK 0x00400000 +#define DSI_VID_MODE_STS_CTL_ERR_BURSTWRITE_EDGE(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_BURSTWRITE_EDGE, __x) +#define DSI_VID_MODE_STS_CTL_ERR_LONGWRITE_EDGE_SHIFT 23 +#define DSI_VID_MODE_STS_CTL_ERR_LONGWRITE_EDGE_MASK 0x00800000 +#define DSI_VID_MODE_STS_CTL_ERR_LONGWRITE_EDGE(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_LONGWRITE_EDGE, __x) +#define DSI_VID_MODE_STS_CTL_ERR_LONGREAD_EDGE_SHIFT 24 +#define DSI_VID_MODE_STS_CTL_ERR_LONGREAD_EDGE_MASK 0x01000000 +#define DSI_VID_MODE_STS_CTL_ERR_LONGREAD_EDGE(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_LONGREAD_EDGE, __x) +#define DSI_VID_MODE_STS_CTL_ERR_VRS_WRONG_LENGTH_EDGE_SHIFT 25 +#define DSI_VID_MODE_STS_CTL_ERR_VRS_WRONG_LENGTH_EDGE_MASK 0x02000000 +#define DSI_VID_MODE_STS_CTL_ERR_VRS_WRONG_LENGTH_EDGE(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, ERR_VRS_WRONG_LENGTH_EDGE, __x) +#define DSI_VID_MODE_STS_CTL_VSG_RECOVERY_EDGE_SHIFT 26 +#define DSI_VID_MODE_STS_CTL_VSG_RECOVERY_EDGE_MASK 0x04000000 +#define DSI_VID_MODE_STS_CTL_VSG_RECOVERY_EDGE(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CTL, VSG_RECOVERY_EDGE, __x) +#define DSI_TG_STS_CTL 0x00000104 +#define DSI_TG_STS_CTL_TVG_STS_EN_SHIFT 0 +#define DSI_TG_STS_CTL_TVG_STS_EN_MASK 0x00000001 +#define DSI_TG_STS_CTL_TVG_STS_EN(__x) \ + DSI_VAL2REG(DSI_TG_STS_CTL, TVG_STS_EN, __x) +#define DSI_TG_STS_CTL_TBG_STS_EN_SHIFT 1 +#define DSI_TG_STS_CTL_TBG_STS_EN_MASK 0x00000002 +#define DSI_TG_STS_CTL_TBG_STS_EN(__x) \ + DSI_VAL2REG(DSI_TG_STS_CTL, TBG_STS_EN, __x) +#define DSI_TG_STS_CTL_TVG_STS_EDGE_SHIFT 16 +#define DSI_TG_STS_CTL_TVG_STS_EDGE_MASK 0x00010000 +#define DSI_TG_STS_CTL_TVG_STS_EDGE(__x) \ + DSI_VAL2REG(DSI_TG_STS_CTL, TVG_STS_EDGE, __x) +#define DSI_TG_STS_CTL_TBG_STS_EDGE_SHIFT 17 +#define DSI_TG_STS_CTL_TBG_STS_EDGE_MASK 0x00020000 +#define DSI_TG_STS_CTL_TBG_STS_EDGE(__x) \ + DSI_VAL2REG(DSI_TG_STS_CTL, TBG_STS_EDGE, __x) +#define DSI_MCTL_DHPY_ERR_CTL 0x00000108 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_1_EN_SHIFT 6 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_1_EN_MASK 0x00000040 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_1_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_ESC_1_EN, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_2_EN_SHIFT 7 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_2_EN_MASK 0x00000080 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_2_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_ESC_2_EN, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_1_EN_SHIFT 8 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_1_EN_MASK 0x00000100 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_1_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_SYNCESC_1_EN, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_2_EN_SHIFT 9 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_2_EN_MASK 0x00000200 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_2_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_SYNCESC_2_EN, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_1_EN_SHIFT 10 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_1_EN_MASK 0x00000400 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_1_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONTROL_1_EN, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_2_EN_SHIFT 11 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_2_EN_MASK 0x00000800 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_2_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONTROL_2_EN, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_1_EN_SHIFT 12 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_1_EN_MASK 0x00001000 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_1_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP0_1_EN, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_2_EN_SHIFT 13 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_2_EN_MASK 0x00002000 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_2_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP0_2_EN, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_1_EN_SHIFT 14 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_1_EN_MASK 0x00004000 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_1_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP1_1_EN, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_2_EN_SHIFT 15 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_2_EN_MASK 0x00008000 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_2_EN(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP1_2_EN, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_1_EDGE_SHIFT 22 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_1_EDGE_MASK 0x00400000 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_1_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_ESC_1_EDGE, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_2_EDGE_SHIFT 23 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_2_EDGE_MASK 0x00800000 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_ESC_2_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_ESC_2_EDGE, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_1_EDGE_SHIFT 24 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_1_EDGE_MASK 0x01000000 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_1_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_SYNCESC_1_EDGE, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_2_EDGE_SHIFT 25 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_2_EDGE_MASK 0x02000000 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_SYNCESC_2_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_SYNCESC_2_EDGE, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_1_EDGE_SHIFT 26 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_1_EDGE_MASK 0x04000000 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_1_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONTROL_1_EDGE, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_2_EDGE_SHIFT 27 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_2_EDGE_MASK 0x08000000 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONTROL_2_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONTROL_2_EDGE, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_1_EDGE_SHIFT 28 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_1_EDGE_MASK 0x10000000 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_1_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP0_1_EDGE, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_2_EDGE_SHIFT 29 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_2_EDGE_MASK 0x20000000 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP0_2_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP0_2_EDGE, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_1_EDGE_SHIFT 30 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_1_EDGE_MASK 0x40000000 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_1_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP1_1_EDGE, __x) +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_2_EDGE_SHIFT 31 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_2_EDGE_MASK 0x80000000 +#define DSI_MCTL_DHPY_ERR_CTL_ERR_CONT_LP1_2_EDGE(__x) \ + DSI_VAL2REG(DSI_MCTL_DHPY_ERR_CTL, ERR_CONT_LP1_2_EDGE, __x) +#define DSI_MCTL_MAIN_STS_CLR 0x00000110 +#define DSI_MCTL_MAIN_STS_CLR_PLL_LOCK_CLR_SHIFT 0 +#define DSI_MCTL_MAIN_STS_CLR_PLL_LOCK_CLR_MASK 0x00000001 +#define DSI_MCTL_MAIN_STS_CLR_PLL_LOCK_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, PLL_LOCK_CLR, __x) +#define DSI_MCTL_MAIN_STS_CLR_CLKLANE_READY_CLR_SHIFT 1 +#define DSI_MCTL_MAIN_STS_CLR_CLKLANE_READY_CLR_MASK 0x00000002 +#define DSI_MCTL_MAIN_STS_CLR_CLKLANE_READY_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, CLKLANE_READY_CLR, __x) +#define DSI_MCTL_MAIN_STS_CLR_DAT1_READY_CLR_SHIFT 2 +#define DSI_MCTL_MAIN_STS_CLR_DAT1_READY_CLR_MASK 0x00000004 +#define DSI_MCTL_MAIN_STS_CLR_DAT1_READY_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, DAT1_READY_CLR, __x) +#define DSI_MCTL_MAIN_STS_CLR_DAT2_READY_CLR_SHIFT 3 +#define DSI_MCTL_MAIN_STS_CLR_DAT2_READY_CLR_MASK 0x00000008 +#define DSI_MCTL_MAIN_STS_CLR_DAT2_READY_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, DAT2_READY_CLR, __x) +#define DSI_MCTL_MAIN_STS_CLR_HSTX_TO_ERR_CLR_SHIFT 4 +#define DSI_MCTL_MAIN_STS_CLR_HSTX_TO_ERR_CLR_MASK 0x00000010 +#define DSI_MCTL_MAIN_STS_CLR_HSTX_TO_ERR_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, HSTX_TO_ERR_CLR, __x) +#define DSI_MCTL_MAIN_STS_CLR_LPRX_TO_ERR_CLR_SHIFT 5 +#define DSI_MCTL_MAIN_STS_CLR_LPRX_TO_ERR_CLR_MASK 0x00000020 +#define DSI_MCTL_MAIN_STS_CLR_LPRX_TO_ERR_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, LPRX_TO_ERR_CLR, __x) +#define DSI_MCTL_MAIN_STS_CLR_CRS_UNTERM_PCK_CLR_SHIFT 6 +#define DSI_MCTL_MAIN_STS_CLR_CRS_UNTERM_PCK_CLR_MASK 0x00000040 +#define DSI_MCTL_MAIN_STS_CLR_CRS_UNTERM_PCK_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, CRS_UNTERM_PCK_CLR, __x) +#define DSI_MCTL_MAIN_STS_CLR_VRS_UNTERM_PCK_CLR_SHIFT 7 +#define DSI_MCTL_MAIN_STS_CLR_VRS_UNTERM_PCK_CLR_MASK 0x00000080 +#define DSI_MCTL_MAIN_STS_CLR_VRS_UNTERM_PCK_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_CLR, VRS_UNTERM_PCK_CLR, __x) +#define DSI_CMD_MODE_STS_CLR 0x00000114 +#define DSI_CMD_MODE_STS_CLR_ERR_NO_TE_CLR_SHIFT 0 +#define DSI_CMD_MODE_STS_CLR_ERR_NO_TE_CLR_MASK 0x00000001 +#define DSI_CMD_MODE_STS_CLR_ERR_NO_TE_CLR(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CLR, ERR_NO_TE_CLR, __x) +#define DSI_CMD_MODE_STS_CLR_ERR_TE_MISS_CLR_SHIFT 1 +#define DSI_CMD_MODE_STS_CLR_ERR_TE_MISS_CLR_MASK 0x00000002 +#define DSI_CMD_MODE_STS_CLR_ERR_TE_MISS_CLR(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CLR, ERR_TE_MISS_CLR, __x) +#define DSI_CMD_MODE_STS_CLR_ERR_SDI1_UNDERRUN_CLR_SHIFT 2 +#define DSI_CMD_MODE_STS_CLR_ERR_SDI1_UNDERRUN_CLR_MASK 0x00000004 +#define DSI_CMD_MODE_STS_CLR_ERR_SDI1_UNDERRUN_CLR(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CLR, ERR_SDI1_UNDERRUN_CLR, __x) +#define DSI_CMD_MODE_STS_CLR_ERR_SDI2_UNDERRUN_CLR_SHIFT 3 +#define DSI_CMD_MODE_STS_CLR_ERR_SDI2_UNDERRUN_CLR_MASK 0x00000008 +#define DSI_CMD_MODE_STS_CLR_ERR_SDI2_UNDERRUN_CLR(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CLR, ERR_SDI2_UNDERRUN_CLR, __x) +#define DSI_CMD_MODE_STS_CLR_ERR_UNWANTED_RD_CLR_SHIFT 4 +#define DSI_CMD_MODE_STS_CLR_ERR_UNWANTED_RD_CLR_MASK 0x00000010 +#define DSI_CMD_MODE_STS_CLR_ERR_UNWANTED_RD_CLR(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CLR, ERR_UNWANTED_RD_CLR, __x) +#define DSI_CMD_MODE_STS_CLR_CSM_RUNNING_CLR_SHIFT 5 +#define DSI_CMD_MODE_STS_CLR_CSM_RUNNING_CLR_MASK 0x00000020 +#define DSI_CMD_MODE_STS_CLR_CSM_RUNNING_CLR(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_CLR, CSM_RUNNING_CLR, __x) +#define DSI_DIRECT_CMD_STS_CLR 0x00000118 +#define DSI_DIRECT_CMD_STS_CLR_CMD_TRANSMISSION_CLR_SHIFT 0 +#define DSI_DIRECT_CMD_STS_CLR_CMD_TRANSMISSION_CLR_MASK 0x00000001 +#define DSI_DIRECT_CMD_STS_CLR_CMD_TRANSMISSION_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, CMD_TRANSMISSION_CLR, __x) +#define DSI_DIRECT_CMD_STS_CLR_WRITE_COMPLETED_CLR_SHIFT 1 +#define DSI_DIRECT_CMD_STS_CLR_WRITE_COMPLETED_CLR_MASK 0x00000002 +#define DSI_DIRECT_CMD_STS_CLR_WRITE_COMPLETED_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, WRITE_COMPLETED_CLR, __x) +#define DSI_DIRECT_CMD_STS_CLR_TRIGGER_COMPLETED_CLR_SHIFT 2 +#define DSI_DIRECT_CMD_STS_CLR_TRIGGER_COMPLETED_CLR_MASK 0x00000004 +#define DSI_DIRECT_CMD_STS_CLR_TRIGGER_COMPLETED_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, TRIGGER_COMPLETED_CLR, __x) +#define DSI_DIRECT_CMD_STS_CLR_READ_COMPLETED_CLR_SHIFT 3 +#define DSI_DIRECT_CMD_STS_CLR_READ_COMPLETED_CLR_MASK 0x00000008 +#define DSI_DIRECT_CMD_STS_CLR_READ_COMPLETED_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, READ_COMPLETED_CLR, __x) +#define DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_RECEIVED_CLR_SHIFT 4 +#define DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_RECEIVED_CLR_MASK 0x00000010 +#define DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_RECEIVED_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, ACKNOWLEDGE_RECEIVED_CLR, __x) +#define DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_WITH_ERR_RECEIVED_CLR_SHIFT 5 +#define DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_WITH_ERR_RECEIVED_CLR_MASK 0x00000020 +#define DSI_DIRECT_CMD_STS_CLR_ACKNOWLEDGE_WITH_ERR_RECEIVED_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, ACKNOWLEDGE_WITH_ERR_RECEIVED_CLR, __x) +#define DSI_DIRECT_CMD_STS_CLR_TRIGGER_RECEIVED_CLR_SHIFT 6 +#define DSI_DIRECT_CMD_STS_CLR_TRIGGER_RECEIVED_CLR_MASK 0x00000040 +#define DSI_DIRECT_CMD_STS_CLR_TRIGGER_RECEIVED_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, TRIGGER_RECEIVED_CLR, __x) +#define DSI_DIRECT_CMD_STS_CLR_TE_RECEIVED_CLR_SHIFT 7 +#define DSI_DIRECT_CMD_STS_CLR_TE_RECEIVED_CLR_MASK 0x00000080 +#define DSI_DIRECT_CMD_STS_CLR_TE_RECEIVED_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, TE_RECEIVED_CLR, __x) +#define DSI_DIRECT_CMD_STS_CLR_BTA_COMPLETED_CLR_SHIFT 8 +#define DSI_DIRECT_CMD_STS_CLR_BTA_COMPLETED_CLR_MASK 0x00000100 +#define DSI_DIRECT_CMD_STS_CLR_BTA_COMPLETED_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, BTA_COMPLETED_CLR, __x) +#define DSI_DIRECT_CMD_STS_CLR_BTA_FINISHED_CLR_SHIFT 9 +#define DSI_DIRECT_CMD_STS_CLR_BTA_FINISHED_CLR_MASK 0x00000200 +#define DSI_DIRECT_CMD_STS_CLR_BTA_FINISHED_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, BTA_FINISHED_CLR, __x) +#define DSI_DIRECT_CMD_STS_CLR_READ_COMPLETED_WITH_ERR_CLR_SHIFT 10 +#define DSI_DIRECT_CMD_STS_CLR_READ_COMPLETED_WITH_ERR_CLR_MASK 0x00000400 +#define DSI_DIRECT_CMD_STS_CLR_READ_COMPLETED_WITH_ERR_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_CLR, READ_COMPLETED_WITH_ERR_CLR, __x) +#define DSI_DIRECT_CMD_RD_STS_CLR 0x0000011C +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_FIXED_CLR_SHIFT 0 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_FIXED_CLR_MASK 0x00000001 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_FIXED_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_FIXED_CLR, __x) +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_UNCORRECTABLE_CLR_SHIFT 1 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_UNCORRECTABLE_CLR_MASK 0x00000002 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_UNCORRECTABLE_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_UNCORRECTABLE_CLR, __x) +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_CHECKSUM_CLR_SHIFT 2 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_CHECKSUM_CLR_MASK 0x00000004 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_CHECKSUM_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_CHECKSUM_CLR, __x) +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_UNDECODABLE_CLR_SHIFT 3 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_UNDECODABLE_CLR_MASK 0x00000008 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_UNDECODABLE_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_UNDECODABLE_CLR, __x) +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_RECEIVE_CLR_SHIFT 4 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_RECEIVE_CLR_MASK 0x00000010 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_RECEIVE_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_RECEIVE_CLR, __x) +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_OVERSIZE_CLR_SHIFT 5 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_OVERSIZE_CLR_MASK 0x00000020 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_OVERSIZE_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_OVERSIZE_CLR, __x) +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_WRONG_LENGTH_CLR_SHIFT 6 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_WRONG_LENGTH_CLR_MASK 0x00000040 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_WRONG_LENGTH_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_WRONG_LENGTH_CLR, __x) +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_MISSING_EOT_CLR_SHIFT 7 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_MISSING_EOT_CLR_MASK 0x00000080 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_MISSING_EOT_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_MISSING_EOT_CLR, __x) +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_EOT_WITH_ERR_CLR_SHIFT 8 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_EOT_WITH_ERR_CLR_MASK 0x00000100 +#define DSI_DIRECT_CMD_RD_STS_CLR_ERR_EOT_WITH_ERR_CLR(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_CLR, ERR_EOT_WITH_ERR_CLR, __x) +#define DSI_VID_MODE_STS_CLR 0x00000120 +#define DSI_VID_MODE_STS_CLR_VSG_STS_CLR_SHIFT 0 +#define DSI_VID_MODE_STS_CLR_VSG_STS_CLR_MASK 0x00000001 +#define DSI_VID_MODE_STS_CLR_VSG_STS_CLR(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CLR, VSG_STS_CLR, __x) +#define DSI_VID_MODE_STS_CLR_ERR_MISSING_DATA_CLR_SHIFT 1 +#define DSI_VID_MODE_STS_CLR_ERR_MISSING_DATA_CLR_MASK 0x00000002 +#define DSI_VID_MODE_STS_CLR_ERR_MISSING_DATA_CLR(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CLR, ERR_MISSING_DATA_CLR, __x) +#define DSI_VID_MODE_STS_CLR_ERR_MISSING_HSYNC_CLR_SHIFT 2 +#define DSI_VID_MODE_STS_CLR_ERR_MISSING_HSYNC_CLR_MASK 0x00000004 +#define DSI_VID_MODE_STS_CLR_ERR_MISSING_HSYNC_CLR(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CLR, ERR_MISSING_HSYNC_CLR, __x) +#define DSI_VID_MODE_STS_CLR_ERR_MISSING_VSYNC_CLR_SHIFT 3 +#define DSI_VID_MODE_STS_CLR_ERR_MISSING_VSYNC_CLR_MASK 0x00000008 +#define DSI_VID_MODE_STS_CLR_ERR_MISSING_VSYNC_CLR(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CLR, ERR_MISSING_VSYNC_CLR, __x) +#define DSI_VID_MODE_STS_CLR_REG_ERR_SMALL_LENGTH_CLR_SHIFT 4 +#define DSI_VID_MODE_STS_CLR_REG_ERR_SMALL_LENGTH_CLR_MASK 0x00000010 +#define DSI_VID_MODE_STS_CLR_REG_ERR_SMALL_LENGTH_CLR(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CLR, REG_ERR_SMALL_LENGTH_CLR, __x) +#define DSI_VID_MODE_STS_CLR_REG_ERR_SMALL_HEIGHT_CLR_SHIFT 5 +#define DSI_VID_MODE_STS_CLR_REG_ERR_SMALL_HEIGHT_CLR_MASK 0x00000020 +#define DSI_VID_MODE_STS_CLR_REG_ERR_SMALL_HEIGHT_CLR(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CLR, REG_ERR_SMALL_HEIGHT_CLR, __x) +#define DSI_VID_MODE_STS_CLR_ERR_BURSTWRITE_CLR_SHIFT 6 +#define DSI_VID_MODE_STS_CLR_ERR_BURSTWRITE_CLR_MASK 0x00000040 +#define DSI_VID_MODE_STS_CLR_ERR_BURSTWRITE_CLR(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CLR, ERR_BURSTWRITE_CLR, __x) +#define DSI_VID_MODE_STS_CLR_ERR_LONGWRITE_CLR_SHIFT 7 +#define DSI_VID_MODE_STS_CLR_ERR_LONGWRITE_CLR_MASK 0x00000080 +#define DSI_VID_MODE_STS_CLR_ERR_LONGWRITE_CLR(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CLR, ERR_LONGWRITE_CLR, __x) +#define DSI_VID_MODE_STS_CLR_ERR_LONGREAD_CLR_SHIFT 8 +#define DSI_VID_MODE_STS_CLR_ERR_LONGREAD_CLR_MASK 0x00000100 +#define DSI_VID_MODE_STS_CLR_ERR_LONGREAD_CLR(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CLR, ERR_LONGREAD_CLR, __x) +#define DSI_VID_MODE_STS_CLR_ERR_VRS_WRONG_LENGTH_CLR_SHIFT 9 +#define DSI_VID_MODE_STS_CLR_ERR_VRS_WRONG_LENGTH_CLR_MASK 0x00000200 +#define DSI_VID_MODE_STS_CLR_ERR_VRS_WRONG_LENGTH_CLR(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CLR, ERR_VRS_WRONG_LENGTH_CLR, __x) +#define DSI_VID_MODE_STS_CLR_VSG_RECOVERY_CLR_SHIFT 10 +#define DSI_VID_MODE_STS_CLR_VSG_RECOVERY_CLR_MASK 0x00000400 +#define DSI_VID_MODE_STS_CLR_VSG_RECOVERY_CLR(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_CLR, VSG_RECOVERY_CLR, __x) +#define DSI_TG_STS_CLR 0x00000124 +#define DSI_TG_STS_CLR_TVG_STS_CLR_SHIFT 0 +#define DSI_TG_STS_CLR_TVG_STS_CLR_MASK 0x00000001 +#define DSI_TG_STS_CLR_TVG_STS_CLR(__x) \ + DSI_VAL2REG(DSI_TG_STS_CLR, TVG_STS_CLR, __x) +#define DSI_TG_STS_CLR_TBG_STS_CLR_SHIFT 1 +#define DSI_TG_STS_CLR_TBG_STS_CLR_MASK 0x00000002 +#define DSI_TG_STS_CLR_TBG_STS_CLR(__x) \ + DSI_VAL2REG(DSI_TG_STS_CLR, TBG_STS_CLR, __x) +#define DSI_MCTL_DPHY_ERR_CLR 0x00000128 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_ESC_1_CLR_SHIFT 6 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_ESC_1_CLR_MASK 0x00000040 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_ESC_1_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_ESC_1_CLR, __x) +#define DSI_MCTL_DPHY_ERR_CLR_ERR_ESC_2_CLR_SHIFT 7 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_ESC_2_CLR_MASK 0x00000080 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_ESC_2_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_ESC_2_CLR, __x) +#define DSI_MCTL_DPHY_ERR_CLR_ERR_SYNCESC_1_CLR_SHIFT 8 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_SYNCESC_1_CLR_MASK 0x00000100 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_SYNCESC_1_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_SYNCESC_1_CLR, __x) +#define DSI_MCTL_DPHY_ERR_CLR_ERR_SYNCESC_2_CLR_SHIFT 9 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_SYNCESC_2_CLR_MASK 0x00000200 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_SYNCESC_2_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_SYNCESC_2_CLR, __x) +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONTROL_1_CLR_SHIFT 10 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONTROL_1_CLR_MASK 0x00000400 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONTROL_1_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_CONTROL_1_CLR, __x) +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONTROL_2_CLR_SHIFT 11 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONTROL_2_CLR_MASK 0x00000800 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONTROL_2_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_CONTROL_2_CLR, __x) +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP0_1_CLR_SHIFT 12 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP0_1_CLR_MASK 0x00001000 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP0_1_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_CONT_LP0_1_CLR, __x) +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP0_2_CLR_SHIFT 13 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP0_2_CLR_MASK 0x00002000 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP0_2_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_CONT_LP0_2_CLR, __x) +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP1_1_CLR_SHIFT 14 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP1_1_CLR_MASK 0x00004000 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP1_1_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_CONT_LP1_1_CLR, __x) +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP1_2_CLR_SHIFT 15 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP1_2_CLR_MASK 0x00008000 +#define DSI_MCTL_DPHY_ERR_CLR_ERR_CONT_LP1_2_CLR(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_CLR, ERR_CONT_LP1_2_CLR, __x) +#define DSI_MCTL_MAIN_STS_FLAG 0x00000130 +#define DSI_MCTL_MAIN_STS_FLAG_PLL_LOCK_FLAG_SHIFT 0 +#define DSI_MCTL_MAIN_STS_FLAG_PLL_LOCK_FLAG_MASK 0x00000001 +#define DSI_MCTL_MAIN_STS_FLAG_PLL_LOCK_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, PLL_LOCK_FLAG, __x) +#define DSI_MCTL_MAIN_STS_FLAG_CLKLANE_READY_FLAG_SHIFT 1 +#define DSI_MCTL_MAIN_STS_FLAG_CLKLANE_READY_FLAG_MASK 0x00000002 +#define DSI_MCTL_MAIN_STS_FLAG_CLKLANE_READY_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, CLKLANE_READY_FLAG, __x) +#define DSI_MCTL_MAIN_STS_FLAG_DAT1_READY_FLAG_SHIFT 2 +#define DSI_MCTL_MAIN_STS_FLAG_DAT1_READY_FLAG_MASK 0x00000004 +#define DSI_MCTL_MAIN_STS_FLAG_DAT1_READY_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, DAT1_READY_FLAG, __x) +#define DSI_MCTL_MAIN_STS_FLAG_DAT2_READY_FLAG_SHIFT 3 +#define DSI_MCTL_MAIN_STS_FLAG_DAT2_READY_FLAG_MASK 0x00000008 +#define DSI_MCTL_MAIN_STS_FLAG_DAT2_READY_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, DAT2_READY_FLAG, __x) +#define DSI_MCTL_MAIN_STS_FLAG_HSTX_TO_ERR_FLAG_SHIFT 4 +#define DSI_MCTL_MAIN_STS_FLAG_HSTX_TO_ERR_FLAG_MASK 0x00000010 +#define DSI_MCTL_MAIN_STS_FLAG_HSTX_TO_ERR_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, HSTX_TO_ERR_FLAG, __x) +#define DSI_MCTL_MAIN_STS_FLAG_LPRX_TO_ERR_FLAG_SHIFT 5 +#define DSI_MCTL_MAIN_STS_FLAG_LPRX_TO_ERR_FLAG_MASK 0x00000020 +#define DSI_MCTL_MAIN_STS_FLAG_LPRX_TO_ERR_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, LPRX_TO_ERR_FLAG, __x) +#define DSI_MCTL_MAIN_STS_FLAG_CRS_UNTERM_PCK_FLAG_SHIFT 6 +#define DSI_MCTL_MAIN_STS_FLAG_CRS_UNTERM_PCK_FLAG_MASK 0x00000040 +#define DSI_MCTL_MAIN_STS_FLAG_CRS_UNTERM_PCK_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, CRS_UNTERM_PCK_FLAG, __x) +#define DSI_MCTL_MAIN_STS_FLAG_VRS_UNTERM_PCK_FLAG_SHIFT 7 +#define DSI_MCTL_MAIN_STS_FLAG_VRS_UNTERM_PCK_FLAG_MASK 0x00000080 +#define DSI_MCTL_MAIN_STS_FLAG_VRS_UNTERM_PCK_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_MAIN_STS_FLAG, VRS_UNTERM_PCK_FLAG, __x) +#define DSI_CMD_MODE_STS_FLAG 0x00000134 +#define DSI_CMD_MODE_STS_FLAG_ERR_NO_TE_FLAG_SHIFT 0 +#define DSI_CMD_MODE_STS_FLAG_ERR_NO_TE_FLAG_MASK 0x00000001 +#define DSI_CMD_MODE_STS_FLAG_ERR_NO_TE_FLAG(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_FLAG, ERR_NO_TE_FLAG, __x) +#define DSI_CMD_MODE_STS_FLAG_ERR_TE_MISS_FLAG_SHIFT 1 +#define DSI_CMD_MODE_STS_FLAG_ERR_TE_MISS_FLAG_MASK 0x00000002 +#define DSI_CMD_MODE_STS_FLAG_ERR_TE_MISS_FLAG(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_FLAG, ERR_TE_MISS_FLAG, __x) +#define DSI_CMD_MODE_STS_FLAG_ERR_SDI1_UNDERRUN_FLAG_SHIFT 2 +#define DSI_CMD_MODE_STS_FLAG_ERR_SDI1_UNDERRUN_FLAG_MASK 0x00000004 +#define DSI_CMD_MODE_STS_FLAG_ERR_SDI1_UNDERRUN_FLAG(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_FLAG, ERR_SDI1_UNDERRUN_FLAG, __x) +#define DSI_CMD_MODE_STS_FLAG_ERR_SDI2_UNDERRUN_FLAG_SHIFT 3 +#define DSI_CMD_MODE_STS_FLAG_ERR_SDI2_UNDERRUN_FLAG_MASK 0x00000008 +#define DSI_CMD_MODE_STS_FLAG_ERR_SDI2_UNDERRUN_FLAG(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_FLAG, ERR_SDI2_UNDERRUN_FLAG, __x) +#define DSI_CMD_MODE_STS_FLAG_ERR_UNWANTED_RD_FLAG_SHIFT 4 +#define DSI_CMD_MODE_STS_FLAG_ERR_UNWANTED_RD_FLAG_MASK 0x00000010 +#define DSI_CMD_MODE_STS_FLAG_ERR_UNWANTED_RD_FLAG(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_FLAG, ERR_UNWANTED_RD_FLAG, __x) +#define DSI_CMD_MODE_STS_FLAG_CSM_RUNNING_FLAG_SHIFT 5 +#define DSI_CMD_MODE_STS_FLAG_CSM_RUNNING_FLAG_MASK 0x00000020 +#define DSI_CMD_MODE_STS_FLAG_CSM_RUNNING_FLAG(__x) \ + DSI_VAL2REG(DSI_CMD_MODE_STS_FLAG, CSM_RUNNING_FLAG, __x) +#define DSI_DIRECT_CMD_STS_FLAG 0x00000138 +#define DSI_DIRECT_CMD_STS_FLAG_CMD_TRANSMISSION_FLAG_SHIFT 0 +#define DSI_DIRECT_CMD_STS_FLAG_CMD_TRANSMISSION_FLAG_MASK 0x00000001 +#define DSI_DIRECT_CMD_STS_FLAG_CMD_TRANSMISSION_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, CMD_TRANSMISSION_FLAG, __x) +#define DSI_DIRECT_CMD_STS_FLAG_WRITE_COMPLETED_FLAG_SHIFT 1 +#define DSI_DIRECT_CMD_STS_FLAG_WRITE_COMPLETED_FLAG_MASK 0x00000002 +#define DSI_DIRECT_CMD_STS_FLAG_WRITE_COMPLETED_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, WRITE_COMPLETED_FLAG, __x) +#define DSI_DIRECT_CMD_STS_FLAG_TRIGGER_COMPLETED_FLAG_SHIFT 2 +#define DSI_DIRECT_CMD_STS_FLAG_TRIGGER_COMPLETED_FLAG_MASK 0x00000004 +#define DSI_DIRECT_CMD_STS_FLAG_TRIGGER_COMPLETED_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, TRIGGER_COMPLETED_FLAG, __x) +#define DSI_DIRECT_CMD_STS_FLAG_READ_COMPLETED_FLAG_SHIFT 3 +#define DSI_DIRECT_CMD_STS_FLAG_READ_COMPLETED_FLAG_MASK 0x00000008 +#define DSI_DIRECT_CMD_STS_FLAG_READ_COMPLETED_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, READ_COMPLETED_FLAG, __x) +#define DSI_DIRECT_CMD_STS_FLAG_ACKNOWLEDGE_RECEIVED_FLAG_SHIFT 4 +#define DSI_DIRECT_CMD_STS_FLAG_ACKNOWLEDGE_RECEIVED_FLAG_MASK 0x00000010 +#define DSI_DIRECT_CMD_STS_FLAG_ACKNOWLEDGE_RECEIVED_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, ACKNOWLEDGE_RECEIVED_FLAG, __x) +#define DSI_DIRECT_CMD_STS_FLAG_ACKNOWLEDGE_WITH_ERR_RECEIVED_FLAG_SHIFT 5 +#define DSI_DIRECT_CMD_STS_FLAG_ACKNOWLEDGE_WITH_ERR_RECEIVED_FLAG_MASK 0x00000020 +#define DSI_DIRECT_CMD_STS_FLAG_ACKNOWLEDGE_WITH_ERR_RECEIVED_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, ACKNOWLEDGE_WITH_ERR_RECEIVED_FLAG, __x) +#define DSI_DIRECT_CMD_STS_FLAG_TRIGGER_RECEIVED_FLAG_SHIFT 6 +#define DSI_DIRECT_CMD_STS_FLAG_TRIGGER_RECEIVED_FLAG_MASK 0x00000040 +#define DSI_DIRECT_CMD_STS_FLAG_TRIGGER_RECEIVED_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, TRIGGER_RECEIVED_FLAG, __x) +#define DSI_DIRECT_CMD_STS_FLAG_TE_RECEIVED_FLAG_SHIFT 7 +#define DSI_DIRECT_CMD_STS_FLAG_TE_RECEIVED_FLAG_MASK 0x00000080 +#define DSI_DIRECT_CMD_STS_FLAG_TE_RECEIVED_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, TE_RECEIVED_FLAG, __x) +#define DSI_DIRECT_CMD_STS_FLAG_BTA_COMPLETED_FLAG_SHIFT 8 +#define DSI_DIRECT_CMD_STS_FLAG_BTA_COMPLETED_FLAG_MASK 0x00000100 +#define DSI_DIRECT_CMD_STS_FLAG_BTA_COMPLETED_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, BTA_COMPLETED_FLAG, __x) +#define DSI_DIRECT_CMD_STS_FLAG_BTA_FINISHED_FLAG_SHIFT 9 +#define DSI_DIRECT_CMD_STS_FLAG_BTA_FINISHED_FLAG_MASK 0x00000200 +#define DSI_DIRECT_CMD_STS_FLAG_BTA_FINISHED_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, BTA_FINISHED_FLAG, __x) +#define DSI_DIRECT_CMD_STS_FLAG_READ_COMPLETED_WITH_ERR_FLAG_SHIFT 10 +#define DSI_DIRECT_CMD_STS_FLAG_READ_COMPLETED_WITH_ERR_FLAG_MASK 0x00000400 +#define DSI_DIRECT_CMD_STS_FLAG_READ_COMPLETED_WITH_ERR_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_STS_FLAG, READ_COMPLETED_WITH_ERR_FLAG, __x) +#define DSI_DIRECT_CMD_RD_STS_FLAG 0x0000013C +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_FIXED_FLAG_SHIFT 0 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_FIXED_FLAG_MASK 0x00000001 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_FIXED_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_FIXED_FLAG, __x) +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_UNCORRECTABLE_FLAG_SHIFT 1 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_UNCORRECTABLE_FLAG_MASK 0x00000002 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_UNCORRECTABLE_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_UNCORRECTABLE_FLAG, __x) +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_CHECKSUM_FLAG_SHIFT 2 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_CHECKSUM_FLAG_MASK 0x00000004 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_CHECKSUM_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_CHECKSUM_FLAG, __x) +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_UNDECODABLE_FLAG_SHIFT 3 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_UNDECODABLE_FLAG_MASK 0x00000008 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_UNDECODABLE_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_UNDECODABLE_FLAG, __x) +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_RECEIVE_FLAG_SHIFT 4 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_RECEIVE_FLAG_MASK 0x00000010 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_RECEIVE_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_RECEIVE_FLAG, __x) +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_OVERSIZE_FLAG_SHIFT 5 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_OVERSIZE_FLAG_MASK 0x00000020 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_OVERSIZE_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_OVERSIZE_FLAG, __x) +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_WRONG_LENGTH_FLAG_SHIFT 6 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_WRONG_LENGTH_FLAG_MASK 0x00000040 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_WRONG_LENGTH_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_WRONG_LENGTH_FLAG, __x) +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_MISSING_EOT_FLAG_SHIFT 7 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_MISSING_EOT_FLAG_MASK 0x00000080 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_MISSING_EOT_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_MISSING_EOT_FLAG, __x) +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_EOT_WITH_ERR_FLAG_SHIFT 8 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_EOT_WITH_ERR_FLAG_MASK 0x00000100 +#define DSI_DIRECT_CMD_RD_STS_FLAG_ERR_EOT_WITH_ERR_FLAG(__x) \ + DSI_VAL2REG(DSI_DIRECT_CMD_RD_STS_FLAG, ERR_EOT_WITH_ERR_FLAG, __x) +#define DSI_VID_MODE_STS_FLAG 0x00000140 +#define DSI_VID_MODE_STS_FLAG_VSG_STS_FLAG_SHIFT 0 +#define DSI_VID_MODE_STS_FLAG_VSG_STS_FLAG_MASK 0x00000001 +#define DSI_VID_MODE_STS_FLAG_VSG_STS_FLAG(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, VSG_STS_FLAG, __x) +#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_DATA_FLAG_SHIFT 1 +#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_DATA_FLAG_MASK 0x00000002 +#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_DATA_FLAG(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, ERR_MISSING_DATA_FLAG, __x) +#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_HSYNC_FLAG_SHIFT 2 +#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_HSYNC_FLAG_MASK 0x00000004 +#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_HSYNC_FLAG(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, ERR_MISSING_HSYNC_FLAG, __x) +#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_VSYNC_FLAG_SHIFT 3 +#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_VSYNC_FLAG_MASK 0x00000008 +#define DSI_VID_MODE_STS_FLAG_ERR_MISSING_VSYNC_FLAG(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, ERR_MISSING_VSYNC_FLAG, __x) +#define DSI_VID_MODE_STS_FLAG_REG_ERR_SMALL_LENGTH_FLAG_SHIFT 4 +#define DSI_VID_MODE_STS_FLAG_REG_ERR_SMALL_LENGTH_FLAG_MASK 0x00000010 +#define DSI_VID_MODE_STS_FLAG_REG_ERR_SMALL_LENGTH_FLAG(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, REG_ERR_SMALL_LENGTH_FLAG, __x) +#define DSI_VID_MODE_STS_FLAG_REG_ERR_SMALL_HEIGHT_FLAG_SHIFT 5 +#define DSI_VID_MODE_STS_FLAG_REG_ERR_SMALL_HEIGHT_FLAG_MASK 0x00000020 +#define DSI_VID_MODE_STS_FLAG_REG_ERR_SMALL_HEIGHT_FLAG(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, REG_ERR_SMALL_HEIGHT_FLAG, __x) +#define DSI_VID_MODE_STS_FLAG_ERR_BURSTWRITE_FLAG_SHIFT 6 +#define DSI_VID_MODE_STS_FLAG_ERR_BURSTWRITE_FLAG_MASK 0x00000040 +#define DSI_VID_MODE_STS_FLAG_ERR_BURSTWRITE_FLAG(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, ERR_BURSTWRITE_FLAG, __x) +#define DSI_VID_MODE_STS_FLAG_ERR_LONGWRITE_FLAG_SHIFT 7 +#define DSI_VID_MODE_STS_FLAG_ERR_LONGWRITE_FLAG_MASK 0x00000080 +#define DSI_VID_MODE_STS_FLAG_ERR_LONGWRITE_FLAG(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, ERR_LONGWRITE_FLAG, __x) +#define DSI_VID_MODE_STS_FLAG_ERR_LONGREAD_FLAG_SHIFT 8 +#define DSI_VID_MODE_STS_FLAG_ERR_LONGREAD_FLAG_MASK 0x00000100 +#define DSI_VID_MODE_STS_FLAG_ERR_LONGREAD_FLAG(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, ERR_LONGREAD_FLAG, __x) +#define DSI_VID_MODE_STS_FLAG_ERR_VRS_WRONG_LENGTH_FLAG_SHIFT 9 +#define DSI_VID_MODE_STS_FLAG_ERR_VRS_WRONG_LENGTH_FLAG_MASK 0x00000200 +#define DSI_VID_MODE_STS_FLAG_ERR_VRS_WRONG_LENGTH_FLAG(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, ERR_VRS_WRONG_LENGTH_FLAG, __x) +#define DSI_VID_MODE_STS_FLAG_VSG_RECOVERY_FLAG_SHIFT 10 +#define DSI_VID_MODE_STS_FLAG_VSG_RECOVERY_FLAG_MASK 0x00000400 +#define DSI_VID_MODE_STS_FLAG_VSG_RECOVERY_FLAG(__x) \ + DSI_VAL2REG(DSI_VID_MODE_STS_FLAG, VSG_RECOVERY_FLAG, __x) +#define DSI_TG_STS_FLAG 0x00000144 +#define DSI_TG_STS_FLAG_TVG_STS_FLAG_SHIFT 0 +#define DSI_TG_STS_FLAG_TVG_STS_FLAG_MASK 0x00000001 +#define DSI_TG_STS_FLAG_TVG_STS_FLAG(__x) \ + DSI_VAL2REG(DSI_TG_STS_FLAG, TVG_STS_FLAG, __x) +#define DSI_TG_STS_FLAG_TBG_STS_FLAG_SHIFT 1 +#define DSI_TG_STS_FLAG_TBG_STS_FLAG_MASK 0x00000002 +#define DSI_TG_STS_FLAG_TBG_STS_FLAG(__x) \ + DSI_VAL2REG(DSI_TG_STS_FLAG, TBG_STS_FLAG, __x) +#define DSI_MCTL_DPHY_ERR_FLAG 0x00000148 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_ESC_1_FLAG_SHIFT 6 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_ESC_1_FLAG_MASK 0x00000040 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_ESC_1_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_ESC_1_FLAG, __x) +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_ESC_2_FLAG_SHIFT 7 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_ESC_2_FLAG_MASK 0x00000080 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_ESC_2_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_ESC_2_FLAG, __x) +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_SYNCESC_1_FLAG_SHIFT 8 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_SYNCESC_1_FLAG_MASK 0x00000100 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_SYNCESC_1_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_SYNCESC_1_FLAG, __x) +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_SYNCESC_2_FLAG_SHIFT 9 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_SYNCESC_2_FLAG_MASK 0x00000200 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_SYNCESC_2_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_SYNCESC_2_FLAG, __x) +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONTROL_1_FLAG_SHIFT 10 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONTROL_1_FLAG_MASK 0x00000400 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONTROL_1_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_CONTROL_1_FLAG, __x) +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONTROL_2_FLAG_SHIFT 11 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONTROL_2_FLAG_MASK 0x00000800 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONTROL_2_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_CONTROL_2_FLAG, __x) +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP0_1_FLAG_SHIFT 12 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP0_1_FLAG_MASK 0x00001000 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP0_1_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_CONT_LP0_1_FLAG, __x) +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP0_2_FLAG_SHIFT 13 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP0_2_FLAG_MASK 0x00002000 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP0_2_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_CONT_LP0_2_FLAG, __x) +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP1_1_FLAG_SHIFT 14 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP1_1_FLAG_MASK 0x00004000 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP1_1_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_CONT_LP1_1_FLAG, __x) +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP1_2_FLAG_SHIFT 15 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP1_2_FLAG_MASK 0x00008000 +#define DSI_MCTL_DPHY_ERR_FLAG_ERR_CONT_LP1_2_FLAG(__x) \ + DSI_VAL2REG(DSI_MCTL_DPHY_ERR_FLAG, ERR_CONT_LP1_2_FLAG, __x) +#define DSI_DPHY_LANES_TRIM 0x00000150 +#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT1_SHIFT 0 +#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT1_MASK 0x00000003 +#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT1(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_SKEW_DAT1, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_CD_OFF_DAT1_SHIFT 2 +#define DSI_DPHY_LANES_TRIM_DPHY_CD_OFF_DAT1_MASK 0x00000004 +#define DSI_DPHY_LANES_TRIM_DPHY_CD_OFF_DAT1(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_CD_OFF_DAT1, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_DAT1_SHIFT 3 +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_DAT1_MASK 0x00000008 +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_DAT1(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_HSTX_SLEWRATE_UP_DAT1, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_DAT1_SHIFT 4 +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_DAT1_MASK 0x00000010 +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_DAT1(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_HSTX_SLEWRATE_DOWN_DAT1, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_DAT1_SHIFT 5 +#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_DAT1_MASK 0x00000020 +#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_DAT1(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_TEST_RESERVED_1_DAT1, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_CLK_SHIFT 6 +#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_CLK_MASK 0x000000C0 +#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_CLK(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_SKEW_CLK, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_LP_RX_VIL_CLK_SHIFT 8 +#define DSI_DPHY_LANES_TRIM_DPHY_LP_RX_VIL_CLK_MASK 0x00000300 +#define DSI_DPHY_LANES_TRIM_DPHY_LP_RX_VIL_CLK(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_LP_RX_VIL_CLK, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_LP_TX_SLEWRATE_CLK_SHIFT 10 +#define DSI_DPHY_LANES_TRIM_DPHY_LP_TX_SLEWRATE_CLK_MASK 0x00000C00 +#define DSI_DPHY_LANES_TRIM_DPHY_LP_TX_SLEWRATE_CLK(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_LP_TX_SLEWRATE_CLK, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_SHIFT 12 +#define DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_MASK 0x00001000 +#define DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_0_81 0 +#define DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_0_90 1 +#define DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_ENUM(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_SPECS_90_81B, \ + DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_##__x) +#define DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_SPECS_90_81B, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_CLK_SHIFT 13 +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_CLK_MASK 0x00002000 +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_CLK(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_HSTX_SLEWRATE_UP_CLK, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_CLK_SHIFT 14 +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_CLK_MASK 0x00004000 +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_CLK(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_HSTX_SLEWRATE_DOWN_CLK, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_CLK_SHIFT 15 +#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_CLK_MASK 0x00008000 +#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_CLK(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_TEST_RESERVED_1_CLK, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT2_SHIFT 16 +#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT2_MASK 0x00030000 +#define DSI_DPHY_LANES_TRIM_DPHY_SKEW_DAT2(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_SKEW_DAT2, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_DAT2_SHIFT 18 +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_DAT2_MASK 0x00040000 +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_UP_DAT2(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_HSTX_SLEWRATE_UP_DAT2, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_DAT2_SHIFT 19 +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_DAT2_MASK 0x00080000 +#define DSI_DPHY_LANES_TRIM_DPHY_HSTX_SLEWRATE_DOWN_DAT2(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_HSTX_SLEWRATE_DOWN_DAT2, __x) +#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_DAT2_SHIFT 20 +#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_DAT2_MASK 0x00100000 +#define DSI_DPHY_LANES_TRIM_DPHY_TEST_RESERVED_1_DAT2(__x) \ + DSI_VAL2REG(DSI_DPHY_LANES_TRIM, DPHY_TEST_RESERVED_1_DAT2, __x) +#define DSI_ID_REG 0x00000FF0 +#define DSI_ID_REG_Y_SHIFT 0 +#define DSI_ID_REG_Y_MASK 0x0000000F +#define DSI_ID_REG_Y(__x) \ + DSI_VAL2REG(DSI_ID_REG, Y, __x) +#define DSI_ID_REG_X_SHIFT 4 +#define DSI_ID_REG_X_MASK 0x000000F0 +#define DSI_ID_REG_X(__x) \ + DSI_VAL2REG(DSI_ID_REG, X, __x) +#define DSI_ID_REG_H_SHIFT 8 +#define DSI_ID_REG_H_MASK 0x00000300 +#define DSI_ID_REG_H(__x) \ + DSI_VAL2REG(DSI_ID_REG, H, __x) +#define DSI_ID_REG_PRODUCT_ID_SHIFT 10 +#define DSI_ID_REG_PRODUCT_ID_MASK 0x0003FC00 +#define DSI_ID_REG_PRODUCT_ID(__x) \ + DSI_VAL2REG(DSI_ID_REG, PRODUCT_ID, __x) +#define DSI_ID_REG_VENDOR_ID_SHIFT 18 +#define DSI_ID_REG_VENDOR_ID_MASK 0xFFFC0000 +#define DSI_ID_REG_VENDOR_ID(__x) \ + DSI_VAL2REG(DSI_ID_REG, VENDOR_ID, __x) +#define DSI_IP_CONF 0x00000FF4 +#define DSI_IP_CONF_FIFO_SIZE_SHIFT 0 +#define DSI_IP_CONF_FIFO_SIZE_MASK 0x0000003F +#define DSI_IP_CONF_FIFO_SIZE(__x) \ + DSI_VAL2REG(DSI_IP_CONF, FIFO_SIZE, __x) diff --git a/drivers/video/mcde/mcde_bus.c b/drivers/video/mcde/mcde_bus.c new file mode 100644 index 00000000000..bdcf65b0fb9 --- /dev/null +++ b/drivers/video/mcde/mcde_bus.c @@ -0,0 +1,274 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * + * ST-Ericsson MCDE display bus driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/export.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/notifier.h> + +#include <video/mcde_display.h> +#include <video/mcde_dss.h> + +#define to_mcde_display_driver(__drv) \ + container_of((__drv), struct mcde_display_driver, driver) + +static BLOCKING_NOTIFIER_HEAD(bus_notifier_list); + +static int mcde_drv_suspend(struct device *_dev, pm_message_t state); +static int mcde_drv_resume(struct device *_dev); +struct bus_type mcde_bus_type; + +static int mcde_suspend_device(struct device *dev, void *data) +{ + pm_message_t* state = (pm_message_t *) data; + if (dev->driver && dev->driver->suspend) + return dev->driver->suspend(dev, *state); + return 0; +} + +static int mcde_resume_device(struct device *dev, void *data) +{ + if (dev->driver && dev->driver->resume) + return dev->driver->resume(dev); + return 0; +} + +/* Bus driver */ + +static int mcde_bus_match(struct device *_dev, struct device_driver *driver) +{ + pr_debug("Matching device %s with driver %s\n", + dev_name(_dev), driver->name); + + return strncmp(dev_name(_dev), driver->name, strlen(driver->name)) == 0; +} + +static int mcde_bus_suspend(struct device *_dev, pm_message_t state) +{ + int ret; + ret = bus_for_each_dev(&mcde_bus_type, NULL, &state, + mcde_suspend_device); + if (ret) { + /* TODO Resume all suspended devices */ + /* mcde_bus_resume(dev); */ + return ret; + } + return 0; +} + +static int mcde_bus_resume(struct device *_dev) +{ + return bus_for_each_dev(&mcde_bus_type, NULL, NULL, mcde_resume_device); +} + +struct bus_type mcde_bus_type = { + .name = "mcde_bus", + .match = mcde_bus_match, + .suspend = mcde_bus_suspend, + .resume = mcde_bus_resume, +}; + +static int mcde_drv_probe(struct device *_dev) +{ + struct mcde_display_driver *drv = to_mcde_display_driver(_dev->driver); + struct mcde_display_device *dev = to_mcde_display_device(_dev); + + return drv->probe(dev); +} + +static int mcde_drv_remove(struct device *_dev) +{ + struct mcde_display_driver *drv = to_mcde_display_driver(_dev->driver); + struct mcde_display_device *dev = to_mcde_display_device(_dev); + + return drv->remove(dev); +} + +static void mcde_drv_shutdown(struct device *_dev) +{ + struct mcde_display_driver *drv = to_mcde_display_driver(_dev->driver); + struct mcde_display_device *dev = to_mcde_display_device(_dev); + + drv->shutdown(dev); +} + +static int mcde_drv_suspend(struct device *_dev, pm_message_t state) +{ + struct mcde_display_driver *drv = to_mcde_display_driver(_dev->driver); + struct mcde_display_device *dev = to_mcde_display_device(_dev); + + if (drv->suspend) + return drv->suspend(dev, state); + else +#if !defined(CONFIG_HAS_EARLYSUSPEND) && defined(CONFIG_PM) + return dev->set_power_mode(dev, MCDE_DISPLAY_PM_OFF); +#else + return 0; +#endif +} + +static int mcde_drv_resume(struct device *_dev) +{ + struct mcde_display_driver *drv = to_mcde_display_driver(_dev->driver); + struct mcde_display_device *dev = to_mcde_display_device(_dev); + + if (drv->resume) + return drv->resume(dev); + else +#if !defined(CONFIG_HAS_EARLYSUSPEND) && defined(CONFIG_PM) + return dev->set_power_mode(dev, MCDE_DISPLAY_PM_STANDBY); +#else + return 0; +#endif +} + +/* Bus device */ + +static void mcde_bus_release(struct device *dev) +{ +} + +struct device mcde_bus = { + .init_name = "mcde_bus", + .release = mcde_bus_release +}; + +/* Public bus API */ + +int mcde_display_driver_register(struct mcde_display_driver *drv) +{ + drv->driver.bus = &mcde_bus_type; + if (drv->probe) + drv->driver.probe = mcde_drv_probe; + if (drv->remove) + drv->driver.remove = mcde_drv_remove; + if (drv->shutdown) + drv->driver.shutdown = mcde_drv_shutdown; + drv->driver.suspend = mcde_drv_suspend; + drv->driver.resume = mcde_drv_resume; + + return driver_register(&drv->driver); +} +EXPORT_SYMBOL(mcde_display_driver_register); + +void mcde_display_driver_unregister(struct mcde_display_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL(mcde_display_driver_unregister); + +static void mcde_display_dev_release(struct device *dev) +{ + /* Do nothing */ +} + +int mcde_display_device_register(struct mcde_display_device *dev) +{ + /* Setup device */ + if (!dev) + return -EINVAL; + dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + dev->dev.bus = &mcde_bus_type; + if (dev->dev.parent != NULL) + dev->dev.parent = &mcde_bus; + dev->dev.release = mcde_display_dev_release; + if (dev->id != -1) + dev_set_name(&dev->dev, "%s.%d", dev->name, dev->id); + else + dev_set_name(&dev->dev, dev->name); + + mcde_display_init_device(dev); + + return device_register(&dev->dev); +} +EXPORT_SYMBOL(mcde_display_device_register); + +void mcde_display_device_unregister(struct mcde_display_device *dev) +{ + device_unregister(&dev->dev); +} +EXPORT_SYMBOL(mcde_display_device_unregister); + +/* Notifications */ +int mcde_dss_register_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&bus_notifier_list, nb); +} +EXPORT_SYMBOL(mcde_dss_register_notifier); + +int mcde_dss_unregister_notifier(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&bus_notifier_list, nb); +} +EXPORT_SYMBOL(mcde_dss_unregister_notifier); + +static int bus_notify_callback(struct notifier_block *nb, + unsigned long event, void *dev) +{ + struct mcde_display_device *ddev = to_mcde_display_device(dev); + + if (event == BUS_NOTIFY_BOUND_DRIVER) { + ddev->initialized = true; + blocking_notifier_call_chain(&bus_notifier_list, + MCDE_DSS_EVENT_DISPLAY_REGISTERED, ddev); + } else if (event == BUS_NOTIFY_UNBIND_DRIVER) { + ddev->initialized = false; + blocking_notifier_call_chain(&bus_notifier_list, + MCDE_DSS_EVENT_DISPLAY_UNREGISTERED, ddev); + } + return 0; +} + +struct notifier_block bus_nb = { + .notifier_call = bus_notify_callback, +}; + +/* Driver init/exit */ + +int __init mcde_display_init(void) +{ + int ret; + + ret = bus_register(&mcde_bus_type); + if (ret) { + pr_warning("Unable to register bus type\n"); + goto no_bus_registration; + } + ret = device_register(&mcde_bus); + if (ret) { + pr_warning("Unable to register bus device\n"); + goto no_device_registration; + } + ret = bus_register_notifier(&mcde_bus_type, &bus_nb); + if (ret) { + pr_warning("Unable to register bus notifier\n"); + goto no_bus_notifier; + } + + goto out; + +no_bus_notifier: + device_unregister(&mcde_bus); +no_device_registration: + bus_unregister(&mcde_bus_type); +no_bus_registration: +out: + return ret; +} + +void mcde_display_exit(void) +{ + bus_unregister_notifier(&mcde_bus_type, &bus_nb); + device_unregister(&mcde_bus); + bus_unregister(&mcde_bus_type); +} diff --git a/drivers/video/mcde/mcde_debugfs.c b/drivers/video/mcde/mcde_debugfs.c new file mode 100644 index 00000000000..586b1787d00 --- /dev/null +++ b/drivers/video/mcde/mcde_debugfs.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson MCDE base driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/stat.h> +#include <linux/time.h> +#include <linux/debugfs.h> +#include <linux/slab.h> +#include <asm/page.h> + +#include "mcde_debugfs.h" + +#define MAX_NUM_OVERLAYS 2 +#define MAX_NUM_CHANNELS 4 +#define DEFAULT_DMESG_FPS_LOG_INTERVAL 100 + +struct fps_info { + u32 enable_dmesg; + u32 interval_ms; + struct timespec timestamp_last; + u32 frame_counter_last; + u32 frame_counter; + u32 fpks; +}; + +struct overlay_info { + u8 id; + struct dentry *dentry; + struct fps_info fps; +}; + +struct channel_info { + u8 id; + struct dentry *dentry; + struct mcde_chnl_state *chnl; + struct fps_info fps; + struct overlay_info overlays[MAX_NUM_OVERLAYS]; +}; + +static struct mcde_info { + struct device *dev; + struct dentry *dentry; + struct channel_info channels[MAX_NUM_CHANNELS]; +} mcde; + +/* Requires: lhs > rhs */ +static inline u32 timespec_ms_diff(struct timespec lhs, struct timespec rhs) +{ + struct timespec tmp_ts = timespec_sub(lhs, rhs); + u64 tmp_ns = (u64)timespec_to_ns(&tmp_ts); + do_div(tmp_ns, NSEC_PER_MSEC); + return (u32)tmp_ns; +} + +/* Returns "frames per 1000 secs", divide by 1000 to get fps with 3 decimals */ +static u32 update_fps(struct fps_info *fps) +{ + struct timespec now; + u32 fpks = 0, ms_since_last, num_frames; + + getrawmonotonic(&now); + fps->frame_counter++; + + ms_since_last = timespec_ms_diff(now, fps->timestamp_last); + num_frames = fps->frame_counter - fps->frame_counter_last; + if (num_frames > 1 && ms_since_last >= fps->interval_ms) { + fpks = (num_frames * 1000000) / ms_since_last; + fps->timestamp_last = now; + fps->frame_counter_last = fps->frame_counter; + fps->fpks = fpks; + } + + return fpks; +} + +static void update_chnl_fps(struct channel_info *ci) +{ + u32 fpks = update_fps(&ci->fps); + if (fpks && ci->fps.enable_dmesg) + dev_info(mcde.dev, "FPS: chnl=%d fps=%d.%.3d\n", ci->id, + fpks / 1000, fpks % 1000); +} + +static void update_ovly_fps(struct channel_info *ci, struct overlay_info *oi) +{ + u32 fpks = update_fps(&oi->fps); + if (fpks && oi->fps.enable_dmesg) + dev_info(mcde.dev, "FPS: ovly=%d.%d fps=%d.%.3d\n", ci->id, + oi->id, fpks / 1000, fpks % 1000); +} + +int mcde_debugfs_create(struct device *dev) +{ + if (mcde.dev) + return -EBUSY; + + mcde.dentry = debugfs_create_dir("mcde", NULL); + if (!mcde.dentry) + return -ENOMEM; + mcde.dev = dev; + + return 0; +} + +static struct channel_info *find_chnl(u8 chnl_id) +{ + if (chnl_id > MAX_NUM_CHANNELS) + return NULL; + return &mcde.channels[chnl_id]; +} + +static struct overlay_info *find_ovly(struct channel_info *ci, u8 ovly_id) +{ + if (!ci || ovly_id >= MAX_NUM_OVERLAYS) + return NULL; + return &ci->overlays[ovly_id]; +} + +static void create_fps_files(struct dentry *dentry, struct fps_info *fps) +{ + debugfs_create_u32("frame_counter", S_IRUGO, dentry, + &fps->frame_counter); + debugfs_create_u32("frames_per_ksecs", S_IRUGO, dentry, &fps->fpks); + debugfs_create_u32("interval_ms", S_IRUGO|S_IWUGO, dentry, + &fps->interval_ms); + debugfs_create_u32("dmesg", S_IRUGO|S_IWUGO, dentry, + &fps->enable_dmesg); +} + +int mcde_debugfs_channel_create(u8 chnl_id, struct mcde_chnl_state *chnl) +{ + struct channel_info *ci = find_chnl(chnl_id); + char name[10]; + + if (!chnl || !ci) + return -EINVAL; + if (ci->chnl) + return -EBUSY; + + snprintf(name, sizeof(name), "chnl%d", chnl_id); + ci->dentry = debugfs_create_dir(name, mcde.dentry); + if (!ci->dentry) + return -ENOMEM; + + create_fps_files(ci->dentry, &ci->fps); + + ci->fps.interval_ms = DEFAULT_DMESG_FPS_LOG_INTERVAL; + ci->id = chnl_id; + ci->chnl = chnl; + + return 0; +} + +int mcde_debugfs_overlay_create(u8 chnl_id, u8 ovly_id) +{ + struct channel_info *ci = find_chnl(chnl_id); + struct overlay_info *oi = find_ovly(ci, ovly_id); + char name[10]; + + if (!oi || !ci || ovly_id >= MAX_NUM_OVERLAYS) + return -EINVAL; + if (oi->dentry) + return -EBUSY; + + snprintf(name, sizeof(name), "ovly%d", ovly_id); + oi->dentry = debugfs_create_dir(name, ci->dentry); + if (!oi->dentry) + return -ENOMEM; + + create_fps_files(oi->dentry, &oi->fps); + + oi->fps.interval_ms = DEFAULT_DMESG_FPS_LOG_INTERVAL; + oi->id = ovly_id; + + return 0; +} + +void mcde_debugfs_channel_update(u8 chnl_id) +{ + struct channel_info *ci = find_chnl(chnl_id); + + if (!ci || !ci->chnl) + return; + + update_chnl_fps(ci); +} + +void mcde_debugfs_overlay_update(u8 chnl_id, u8 ovly_id) +{ + struct channel_info *ci = find_chnl(chnl_id); + struct overlay_info *oi = find_ovly(ci, ovly_id); + + if (!oi || !oi->dentry) + return; + + update_ovly_fps(ci, oi); +} + diff --git a/drivers/video/mcde/mcde_debugfs.h b/drivers/video/mcde/mcde_debugfs.h new file mode 100644 index 00000000000..9f1e7f18ea5 --- /dev/null +++ b/drivers/video/mcde/mcde_debugfs.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson MCDE base driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __MCDE_DEBUGFS__H__ +#define __MCDE_DEBUGFS__H__ + +#include <video/mcde.h> + +int mcde_debugfs_create(struct device *dev); +int mcde_debugfs_channel_create(u8 chnl_id, struct mcde_chnl_state *chnl); +int mcde_debugfs_overlay_create(u8 chnl_id, u8 ovly_id); + +void mcde_debugfs_channel_update(u8 chnl_id); +void mcde_debugfs_overlay_update(u8 chnl_id, u8 ovly_id); + +#endif /* __MCDE_DEBUGFS__H__ */ + diff --git a/drivers/video/mcde/mcde_display.c b/drivers/video/mcde/mcde_display.c new file mode 100644 index 00000000000..a461b36c9b6 --- /dev/null +++ b/drivers/video/mcde/mcde_display.c @@ -0,0 +1,416 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson MCDE display driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/device.h> + +#include <video/mcde_display.h> + +/*temp*/ +#include <linux/delay.h> + +static void mcde_display_get_native_resolution_default( + struct mcde_display_device *ddev, u16 *x_res, u16 *y_res) +{ + if (x_res) + *x_res = ddev->native_x_res; + if (y_res) + *y_res = ddev->native_y_res; +} + +static enum mcde_ovly_pix_fmt mcde_display_get_default_pixel_format_default( + struct mcde_display_device *ddev) +{ + return ddev->default_pixel_format; +} + +static void mcde_display_get_physical_size_default( + struct mcde_display_device *ddev, u16 *width, u16 *height) +{ + if (width) + *width = ddev->physical_width; + if (height) + *height = ddev->physical_height; +} + +static int mcde_display_set_power_mode_default(struct mcde_display_device *ddev, + enum mcde_display_power_mode power_mode) +{ + int ret = 0; + + /* OFF -> STANDBY */ + if (ddev->power_mode == MCDE_DISPLAY_PM_OFF && + power_mode != MCDE_DISPLAY_PM_OFF) { + if (ddev->platform_enable) { + ret = ddev->platform_enable(ddev); + if (ret) + return ret; + } + ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; + /* force register settings */ + if (ddev->port->type == MCDE_PORTTYPE_DPI) + ddev->update_flags = UPDATE_FLAG_VIDEO_MODE | UPDATE_FLAG_PIXEL_FORMAT; + } + + if (ddev->port->type == MCDE_PORTTYPE_DSI) { + /* STANDBY -> ON */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && + power_mode == MCDE_DISPLAY_PM_ON) { + ret = mcde_dsi_dcs_write(ddev->chnl_state, + DCS_CMD_EXIT_SLEEP_MODE, NULL, 0); + if (ret) + return ret; + + ret = mcde_dsi_dcs_write(ddev->chnl_state, + DCS_CMD_SET_DISPLAY_ON, NULL, 0); + if (ret) + return ret; + + ddev->power_mode = MCDE_DISPLAY_PM_ON; + } else if (ddev->power_mode == MCDE_DISPLAY_PM_ON && + power_mode <= MCDE_DISPLAY_PM_STANDBY) { + /* ON -> STANDBY */ + ret = mcde_dsi_dcs_write(ddev->chnl_state, + DCS_CMD_SET_DISPLAY_OFF, NULL, 0); + if (ret) + return ret; + + ret = mcde_dsi_dcs_write(ddev->chnl_state, + DCS_CMD_ENTER_SLEEP_MODE, NULL, 0); + if (ret) + return ret; + + ddev->power_mode = MCDE_DISPLAY_PM_STANDBY; + } + } else if (ddev->port->type == MCDE_PORTTYPE_DPI) { + ddev->power_mode = power_mode; + } else if (ddev->power_mode != power_mode) { + return -EINVAL; + } + + /* SLEEP -> OFF */ + if (ddev->power_mode == MCDE_DISPLAY_PM_STANDBY && + power_mode == MCDE_DISPLAY_PM_OFF) { + if (ddev->platform_disable) { + ret = ddev->platform_disable(ddev); + if (ret) + return ret; + } + ddev->power_mode = MCDE_DISPLAY_PM_OFF; + } + + mcde_chnl_set_power_mode(ddev->chnl_state, ddev->power_mode); + + return ret; +} + +static inline enum mcde_display_power_mode mcde_display_get_power_mode_default( + struct mcde_display_device *ddev) +{ + return ddev->power_mode; +} + +static inline int mcde_display_try_video_mode_default( + struct mcde_display_device *ddev, + struct mcde_video_mode *video_mode) +{ + /* + * DSI video mode: + * This function is intended for configuring supported video mode(s). + * Overload it into the panel driver file and set up blanking + * intervals and pixel clock according to below recommendations. + * + * vertical blanking parameters vbp, vfp, vsw are given in lines + * horizontal blanking parameters hbp, hfp, hsw are given in pixels + * + * video_mode->pixclock is the time between two pixels (in picoseconds) + * The source of the pixel clock is DSI PLL and it shall be set to + * meet the requirement + * + * non-burst mode: + * pixel clock (Hz) = (VACT+VBP+VFP+VSA) * (HACT+HBP+HFP+HSA) * + * framerate * bpp / num_data_lanes + * + * burst mode: + * pixel clock (Hz) > (VACT+VBP+VFP+VSA) * (HACT+HBP+HFP+HSA) * + * framerate * bpp / num_data_lanes * 1.1 + * (1.1 is a 10% margin needed for burst mode calculations) + */ + return 0; +} + +static int mcde_display_set_video_mode_default(struct mcde_display_device *ddev, + struct mcde_video_mode *video_mode) +{ + int ret; + struct mcde_video_mode channel_video_mode; + + if (!video_mode) + return -EINVAL; + + ddev->video_mode = *video_mode; + channel_video_mode = ddev->video_mode; + /* Dependant on if display should rotate or MCDE should rotate */ + if (ddev->rotation == MCDE_DISPLAY_ROT_90_CCW || + ddev->rotation == MCDE_DISPLAY_ROT_90_CW) { + channel_video_mode.xres = ddev->native_x_res; + channel_video_mode.yres = ddev->native_y_res; + } + ret = mcde_chnl_set_video_mode(ddev->chnl_state, &channel_video_mode); + if (ret < 0) { + dev_warn(&ddev->dev, "%s:Failed to set video mode\n", __func__); + return ret; + } + + ddev->update_flags |= UPDATE_FLAG_VIDEO_MODE; + + return 0; +} + +static inline void mcde_display_get_video_mode_default( + struct mcde_display_device *ddev, struct mcde_video_mode *video_mode) +{ + if (video_mode) + *video_mode = ddev->video_mode; +} + +static int mcde_display_set_pixel_format_default( + struct mcde_display_device *ddev, enum mcde_ovly_pix_fmt format) +{ + int ret; + + ddev->pixel_format = format; + ret = mcde_chnl_set_pixel_format(ddev->chnl_state, + ddev->port->pixel_format); + if (ret < 0) { + dev_warn(&ddev->dev, "%s:Failed to set pixel format = %d\n", + __func__, format); + return ret; + } + + return 0; +} + +static inline enum mcde_ovly_pix_fmt mcde_display_get_pixel_format_default( + struct mcde_display_device *ddev) +{ + return ddev->pixel_format; +} + + +static int mcde_display_set_rotation_default(struct mcde_display_device *ddev, + enum mcde_display_rotation rotation) +{ + int ret; + + ret = mcde_chnl_set_rotation(ddev->chnl_state, rotation, + ddev->rotbuf1, ddev->rotbuf2); + if (ret < 0) { + dev_warn(&ddev->dev, "%s:Failed to set rotation = %d\n", + __func__, rotation); + return ret; + } + + if (rotation == MCDE_DISPLAY_ROT_180_CCW) { + u8 param = 0x40; + (void) mcde_dsi_dcs_write(ddev->chnl_state, + DCS_CMD_SET_ADDRESS_MODE, ¶m, 1); + } else if (ddev->rotation == MCDE_DISPLAY_ROT_180_CCW && + rotation != MCDE_DISPLAY_ROT_180_CCW) { + u8 param = 0; + (void) mcde_dsi_dcs_write(ddev->chnl_state, + DCS_CMD_SET_ADDRESS_MODE, ¶m, 1); + } + + ddev->rotation = rotation; + ddev->update_flags |= UPDATE_FLAG_ROTATION; + + return 0; +} + +static inline enum mcde_display_rotation mcde_display_get_rotation_default( + struct mcde_display_device *ddev) +{ + return ddev->rotation; +} + +static int mcde_display_set_synchronized_update_default( + struct mcde_display_device *ddev, bool enable) +{ + if (ddev->port->type == MCDE_PORTTYPE_DSI && enable) { + int ret; + u8 m = 0; + + if (ddev->port->sync_src == MCDE_SYNCSRC_OFF) + return -EINVAL; + + ret = mcde_dsi_dcs_write(ddev->chnl_state, + DCS_CMD_SET_TEAR_ON, &m, 1); + if (ret < 0) { + dev_warn(&ddev->dev, + "%s:Failed to set synchornized update = %d\n", + __func__, enable); + return ret; + } + } + ddev->synchronized_update = enable; + return 0; +} + +static inline bool mcde_display_get_synchronized_update_default( + struct mcde_display_device *ddev) +{ + return ddev->synchronized_update; +} + +static int mcde_display_apply_config_default(struct mcde_display_device *ddev) +{ + int ret; + + ret = mcde_chnl_enable_synchronized_update(ddev->chnl_state, + ddev->synchronized_update); + + if (ret < 0) { + dev_warn(&ddev->dev, + "%s:Failed to enable synchronized update\n", + __func__); + return ret; + } + + if (!ddev->update_flags) + return 0; + + if (ddev->update_flags & UPDATE_FLAG_VIDEO_MODE) + mcde_chnl_stop_flow(ddev->chnl_state); + + ret = mcde_chnl_apply(ddev->chnl_state); + if (ret < 0) { + dev_warn(&ddev->dev, "%s:Failed to apply to channel\n", + __func__); + return ret; + } + ddev->update_flags = 0; + ddev->first_update = true; + + return 0; +} + +static int mcde_display_invalidate_area_default( + struct mcde_display_device *ddev, + struct mcde_rectangle *area) +{ + dev_vdbg(&ddev->dev, "%s\n", __func__); + if (area) { + /* take union of rects */ + u16 t; + t = min(ddev->update_area.x, area->x); + /* note should be > 0 */ + ddev->update_area.w = max(ddev->update_area.x + + ddev->update_area.w, + area->x + area->w) - t; + ddev->update_area.x = t; + t = min(ddev->update_area.y, area->y); + ddev->update_area.h = max(ddev->update_area.y + + ddev->update_area.h, + area->y + area->h) - t; + ddev->update_area.y = t; + /* TODO: Implement real clipping when partial refresh is + activated.*/ + ddev->update_area.w = min((u16) ddev->video_mode.xres, + (u16) ddev->update_area.w); + ddev->update_area.h = min((u16) ddev->video_mode.yres, + (u16) ddev->update_area.h); + } else { + ddev->update_area.x = 0; + ddev->update_area.y = 0; + ddev->update_area.w = ddev->video_mode.xres; + ddev->update_area.h = ddev->video_mode.yres; + /* Invalidate_area(ddev, NULL) means reset area to empty + * rectangle really. After that the rectangle should grow by + * taking an union (above). This means that the code should + * really look like below, however the code above is a temp fix + * for rotation. + * TODO: fix + * ddev->update_area.x = ddev->video_mode.xres; + * ddev->update_area.y = ddev->video_mode.yres; + * ddev->update_area.w = 0; + * ddev->update_area.h = 0; + */ + } + + return 0; +} + +static int mcde_display_update_default(struct mcde_display_device *ddev, + bool tripple_buffer) +{ + int ret = 0; + + ret = mcde_chnl_update(ddev->chnl_state, &ddev->update_area, + tripple_buffer); + if (ret < 0) { + dev_warn(&ddev->dev, "%s:Failed to update channel\n", __func__); + return ret; + } + if (ddev->first_update && ddev->on_first_update) + ddev->on_first_update(ddev); + + if (ddev->power_mode != MCDE_DISPLAY_PM_ON && ddev->set_power_mode) { + ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_ON); + if (ret < 0) { + dev_warn(&ddev->dev, + "%s:Failed to set power mode to on\n", + __func__); + return ret; + } + } + + dev_vdbg(&ddev->dev, "Overlay updated, chnl=%d\n", ddev->chnl_id); + + return 0; +} + +static inline int mcde_display_on_first_update_default( + struct mcde_display_device *ddev) +{ + ddev->first_update = false; + return 0; +} + +void mcde_display_init_device(struct mcde_display_device *ddev) +{ + /* Setup default callbacks */ + ddev->get_native_resolution = + mcde_display_get_native_resolution_default; + ddev->get_default_pixel_format = + mcde_display_get_default_pixel_format_default; + ddev->get_physical_size = mcde_display_get_physical_size_default; + ddev->set_power_mode = mcde_display_set_power_mode_default; + ddev->get_power_mode = mcde_display_get_power_mode_default; + ddev->try_video_mode = mcde_display_try_video_mode_default; + ddev->set_video_mode = mcde_display_set_video_mode_default; + ddev->get_video_mode = mcde_display_get_video_mode_default; + ddev->set_pixel_format = mcde_display_set_pixel_format_default; + ddev->get_pixel_format = mcde_display_get_pixel_format_default; + ddev->set_rotation = mcde_display_set_rotation_default; + ddev->get_rotation = mcde_display_get_rotation_default; + ddev->set_synchronized_update = + mcde_display_set_synchronized_update_default; + ddev->get_synchronized_update = + mcde_display_get_synchronized_update_default; + ddev->apply_config = mcde_display_apply_config_default; + ddev->invalidate_area = mcde_display_invalidate_area_default; + ddev->update = mcde_display_update_default; + ddev->on_first_update = mcde_display_on_first_update_default; + + mutex_init(&ddev->display_lock); +} + diff --git a/drivers/video/mcde/mcde_dss.c b/drivers/video/mcde/mcde_dss.c new file mode 100644 index 00000000000..044e39ad285 --- /dev/null +++ b/drivers/video/mcde/mcde_dss.c @@ -0,0 +1,479 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson MCDE display sub system driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/export.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/slab.h> + +#include <video/mcde_dss.h> + +#define to_overlay(x) container_of(x, struct mcde_overlay, kobj) + +void overlay_release(struct kobject *kobj) +{ + struct mcde_overlay *ovly = to_overlay(kobj); + + kfree(ovly); +} + +struct kobj_type ovly_type = { + .release = overlay_release, +}; + +static int apply_overlay(struct mcde_overlay *ovly, + struct mcde_overlay_info *info, bool force) +{ + int ret = 0; + if (ovly->ddev->invalidate_area) { + /* TODO: transform ovly coord to screen coords (vmode): + * add offset + */ + struct mcde_rectangle dirty = info->dirty; + mutex_lock(&ovly->ddev->display_lock); + ret = ovly->ddev->invalidate_area(ovly->ddev, &dirty); + mutex_unlock(&ovly->ddev->display_lock); + } + + if (ovly->info.paddr != info->paddr || force) + mcde_ovly_set_source_buf(ovly->state, info->paddr); + + if (ovly->info.stride != info->stride || ovly->info.fmt != info->fmt || + force) + mcde_ovly_set_source_info(ovly->state, info->stride, info->fmt); + if (ovly->info.src_x != info->src_x || + ovly->info.src_y != info->src_y || + ovly->info.w != info->w || + ovly->info.h != info->h || force) + mcde_ovly_set_source_area(ovly->state, + info->src_x, info->src_y, info->w, info->h); + if (ovly->info.dst_x != info->dst_x || ovly->info.dst_y != info->dst_y + || ovly->info.dst_z != info->dst_z || + force) + mcde_ovly_set_dest_pos(ovly->state, + info->dst_x, info->dst_y, info->dst_z); + + mcde_ovly_apply(ovly->state); + ovly->info = *info; + + return ret; +} + +/* MCDE DSS operations */ + +int mcde_dss_open_channel(struct mcde_display_device *ddev) +{ + int ret = 0; + struct mcde_chnl_state *chnl; + + mutex_lock(&ddev->display_lock); + /* Acquire MCDE resources */ + chnl = mcde_chnl_get(ddev->chnl_id, ddev->fifo, ddev->port); + if (IS_ERR(chnl)) { + ret = PTR_ERR(chnl); + dev_warn(&ddev->dev, "Failed to acquire MCDE channel\n"); + goto chnl_get_failed; + } + ddev->chnl_state = chnl; +chnl_get_failed: + mutex_unlock(&ddev->display_lock); + return ret; +} +EXPORT_SYMBOL(mcde_dss_open_channel); + +void mcde_dss_close_channel(struct mcde_display_device *ddev) +{ + mutex_lock(&ddev->display_lock); + mcde_chnl_put(ddev->chnl_state); + ddev->chnl_state = NULL; + mutex_unlock(&ddev->display_lock); +} +EXPORT_SYMBOL(mcde_dss_close_channel); + +int mcde_dss_enable_display(struct mcde_display_device *ddev) +{ + int ret; + + if (ddev->enabled) + return 0; + + mutex_lock(&ddev->display_lock); + mcde_chnl_enable(ddev->chnl_state); + + /* Initiate display communication */ + ret = ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_STANDBY); + if (ret < 0) { + dev_warn(&ddev->dev, "Failed to initialize display\n"); + goto display_failed; + } + + ret = ddev->set_synchronized_update(ddev, + ddev->get_synchronized_update(ddev)); + if (ret < 0) + dev_warn(&ddev->dev, "Failed to set sync\n"); + + ret = mcde_chnl_enable_synchronized_update(ddev->chnl_state, + ddev->synchronized_update); + if (ret < 0) { + dev_warn(&ddev->dev, + "%s:Failed to enable synchronized update\n", + __func__); + goto enable_sync_failed; + } + /* TODO: call driver for all defaults like sync_update above */ + + dev_dbg(&ddev->dev, "Display enabled, chnl=%d\n", + ddev->chnl_id); + ddev->enabled = true; + mutex_unlock(&ddev->display_lock); + + return 0; + +enable_sync_failed: + ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF); +display_failed: + mcde_chnl_disable(ddev->chnl_state); + mutex_unlock(&ddev->display_lock); + return ret; +} +EXPORT_SYMBOL(mcde_dss_enable_display); + +void mcde_dss_disable_display(struct mcde_display_device *ddev) +{ + if (!ddev->enabled) + return; + + /* TODO: Disable overlays */ + mutex_lock(&ddev->display_lock); + + mcde_chnl_stop_flow(ddev->chnl_state); + + (void)ddev->set_power_mode(ddev, MCDE_DISPLAY_PM_OFF); + + mcde_chnl_disable(ddev->chnl_state); + + ddev->enabled = false; + mutex_unlock(&ddev->display_lock); + + dev_dbg(&ddev->dev, "Display disabled, chnl=%d\n", ddev->chnl_id); +} +EXPORT_SYMBOL(mcde_dss_disable_display); + +int mcde_dss_apply_channel(struct mcde_display_device *ddev) +{ + int ret; + if (!ddev->apply_config) + return -EINVAL; + mutex_lock(&ddev->display_lock); + ret = ddev->apply_config(ddev); + mutex_unlock(&ddev->display_lock); + + return ret; +} +EXPORT_SYMBOL(mcde_dss_apply_channel); + +struct mcde_overlay *mcde_dss_create_overlay(struct mcde_display_device *ddev, + struct mcde_overlay_info *info) +{ + struct mcde_overlay *ovly; + + ovly = kzalloc(sizeof(struct mcde_overlay), GFP_KERNEL); + if (!ovly) + return NULL; + + kobject_init(&ovly->kobj, &ovly_type); /* Local ref */ + kobject_get(&ovly->kobj); /* Creator ref */ + INIT_LIST_HEAD(&ovly->list); + mutex_lock(&ddev->display_lock); + list_add(&ddev->ovlys, &ovly->list); + mutex_unlock(&ddev->display_lock); + ovly->info = *info; + ovly->ddev = ddev; + + return ovly; +} +EXPORT_SYMBOL(mcde_dss_create_overlay); + +void mcde_dss_destroy_overlay(struct mcde_overlay *ovly) +{ + list_del(&ovly->list); + if (ovly->state) + mcde_dss_disable_overlay(ovly); + kobject_put(&ovly->kobj); +} +EXPORT_SYMBOL(mcde_dss_destroy_overlay); + +int mcde_dss_enable_overlay(struct mcde_overlay *ovly) +{ + int ret; + + if (!ovly->ddev->chnl_state) + return -EINVAL; + + if (!ovly->state) { + struct mcde_ovly_state *state; + state = mcde_ovly_get(ovly->ddev->chnl_state); + if (IS_ERR(state)) { + ret = PTR_ERR(state); + dev_warn(&ovly->ddev->dev, + "Failed to acquire overlay\n"); + return ret; + } + ovly->state = state; + } + + apply_overlay(ovly, &ovly->info, true); + + dev_vdbg(&ovly->ddev->dev, "Overlay enabled, chnl=%d\n", + ovly->ddev->chnl_id); + return 0; +} +EXPORT_SYMBOL(mcde_dss_enable_overlay); + +int mcde_dss_apply_overlay(struct mcde_overlay *ovly, + struct mcde_overlay_info *info) +{ + if (info == NULL) + info = &ovly->info; + return apply_overlay(ovly, info, false); +} +EXPORT_SYMBOL(mcde_dss_apply_overlay); + +void mcde_dss_disable_overlay(struct mcde_overlay *ovly) +{ + if (!ovly->state) + return; + + mcde_ovly_put(ovly->state); + + dev_dbg(&ovly->ddev->dev, "Overlay disabled, chnl=%d\n", + ovly->ddev->chnl_id); + + ovly->state = NULL; +} +EXPORT_SYMBOL(mcde_dss_disable_overlay); + +int mcde_dss_update_overlay(struct mcde_overlay *ovly, bool tripple_buffer) +{ + int ret; + dev_vdbg(&ovly->ddev->dev, "Overlay update, chnl=%d\n", + ovly->ddev->chnl_id); + + if (!ovly->state || !ovly->ddev->update || !ovly->ddev->invalidate_area) + return -EINVAL; + + mutex_lock(&ovly->ddev->display_lock); + /* Do not perform an update if power mode is off */ + if (ovly->ddev->get_power_mode(ovly->ddev) == MCDE_DISPLAY_PM_OFF) { + ret = 0; + goto power_mode_off; + } + + ret = ovly->ddev->update(ovly->ddev, tripple_buffer); + if (ret) + goto update_failed; + + ret = ovly->ddev->invalidate_area(ovly->ddev, NULL); + +power_mode_off: +update_failed: + mutex_unlock(&ovly->ddev->display_lock); + return ret; +} +EXPORT_SYMBOL(mcde_dss_update_overlay); + +void mcde_dss_get_overlay_info(struct mcde_overlay *ovly, + struct mcde_overlay_info *info) { + if (info) + *info = ovly->info; +} +EXPORT_SYMBOL(mcde_dss_get_overlay_info); + +void mcde_dss_get_native_resolution(struct mcde_display_device *ddev, + u16 *x_res, u16 *y_res) +{ + mutex_lock(&ddev->display_lock); + ddev->get_native_resolution(ddev, x_res, y_res); + mutex_unlock(&ddev->display_lock); +} +EXPORT_SYMBOL(mcde_dss_get_native_resolution); + +enum mcde_ovly_pix_fmt mcde_dss_get_default_pixel_format( + struct mcde_display_device *ddev) +{ + int ret; + mutex_lock(&ddev->display_lock); + ret = ddev->get_default_pixel_format(ddev); + mutex_unlock(&ddev->display_lock); + return ret; +} +EXPORT_SYMBOL(mcde_dss_get_default_pixel_format); + +void mcde_dss_get_physical_size(struct mcde_display_device *ddev, + u16 *physical_width, u16 *physical_height) +{ + mutex_lock(&ddev->display_lock); + ddev->get_physical_size(ddev, physical_width, physical_height); + mutex_unlock(&ddev->display_lock); +} +EXPORT_SYMBOL(mcde_dss_get_physical_size); + +int mcde_dss_try_video_mode(struct mcde_display_device *ddev, + struct mcde_video_mode *video_mode) +{ + int ret; + mutex_lock(&ddev->display_lock); + ret = ddev->try_video_mode(ddev, video_mode); + mutex_unlock(&ddev->display_lock); + return ret; +} +EXPORT_SYMBOL(mcde_dss_try_video_mode); + +int mcde_dss_set_video_mode(struct mcde_display_device *ddev, + struct mcde_video_mode *vmode) +{ + int ret = 0; + struct mcde_video_mode old_vmode; + + mutex_lock(&ddev->display_lock); + /* Do not perform set_video_mode if power mode is off */ + if (ddev->get_power_mode(ddev) == MCDE_DISPLAY_PM_OFF) + goto power_mode_off; + + ddev->get_video_mode(ddev, &old_vmode); + if (memcmp(vmode, &old_vmode, sizeof(old_vmode)) == 0) + goto same_video_mode; + + ret = ddev->set_video_mode(ddev, vmode); + if (ret) + goto set_video_mode_failed; + + if (ddev->invalidate_area) + ret = ddev->invalidate_area(ddev, NULL); +power_mode_off: +same_video_mode: +set_video_mode_failed: + mutex_unlock(&ddev->display_lock); + return ret; +} +EXPORT_SYMBOL(mcde_dss_set_video_mode); + +void mcde_dss_get_video_mode(struct mcde_display_device *ddev, + struct mcde_video_mode *video_mode) +{ + mutex_lock(&ddev->display_lock); + ddev->get_video_mode(ddev, video_mode); + mutex_unlock(&ddev->display_lock); +} +EXPORT_SYMBOL(mcde_dss_get_video_mode); + +int mcde_dss_set_pixel_format(struct mcde_display_device *ddev, + enum mcde_ovly_pix_fmt pix_fmt) +{ + enum mcde_ovly_pix_fmt old_pix_fmt; + int ret; + + mutex_lock(&ddev->display_lock); + old_pix_fmt = ddev->get_pixel_format(ddev); + if (old_pix_fmt == pix_fmt) { + ret = 0; + goto same_pixel_format; + } + + ret = ddev->set_pixel_format(ddev, pix_fmt); + +same_pixel_format: + mutex_unlock(&ddev->display_lock); + return ret; +} +EXPORT_SYMBOL(mcde_dss_set_pixel_format); + +int mcde_dss_get_pixel_format(struct mcde_display_device *ddev) +{ + int ret; + mutex_lock(&ddev->display_lock); + ret = ddev->get_pixel_format(ddev); + mutex_unlock(&ddev->display_lock); + return ret; +} +EXPORT_SYMBOL(mcde_dss_get_pixel_format); + +int mcde_dss_set_rotation(struct mcde_display_device *ddev, + enum mcde_display_rotation rotation) +{ + int ret; + enum mcde_display_rotation old_rotation; + + mutex_lock(&ddev->display_lock); + old_rotation = ddev->get_rotation(ddev); + if (old_rotation == rotation) { + ret = 0; + goto same_rotation; + } + + ret = ddev->set_rotation(ddev, rotation); +same_rotation: + mutex_unlock(&ddev->display_lock); + return ret; +} +EXPORT_SYMBOL(mcde_dss_set_rotation); + +enum mcde_display_rotation mcde_dss_get_rotation( + struct mcde_display_device *ddev) +{ + int ret; + mutex_lock(&ddev->display_lock); + ret = ddev->get_rotation(ddev); + mutex_unlock(&ddev->display_lock); + return ret; +} +EXPORT_SYMBOL(mcde_dss_get_rotation); + +int mcde_dss_set_synchronized_update(struct mcde_display_device *ddev, + bool enable) +{ + int ret; + mutex_lock(&ddev->display_lock); + ret = ddev->set_synchronized_update(ddev, enable); + if (ret) + goto sync_update_failed; + + if (ddev->chnl_state) + mcde_chnl_enable_synchronized_update(ddev->chnl_state, enable); + mutex_unlock(&ddev->display_lock); + return 0; + +sync_update_failed: + mutex_unlock(&ddev->display_lock); + return ret; +} +EXPORT_SYMBOL(mcde_dss_set_synchronized_update); + +bool mcde_dss_get_synchronized_update(struct mcde_display_device *ddev) +{ + int ret; + mutex_lock(&ddev->display_lock); + ret = ddev->get_synchronized_update(ddev); + mutex_unlock(&ddev->display_lock); + return ret; +} +EXPORT_SYMBOL(mcde_dss_get_synchronized_update); + +int __init mcde_dss_init(void) +{ + return 0; +} + +void mcde_dss_exit(void) +{ +} + diff --git a/drivers/video/mcde/mcde_fb.c b/drivers/video/mcde/mcde_fb.c new file mode 100644 index 00000000000..7d877ec3e4f --- /dev/null +++ b/drivers/video/mcde/mcde_fb.c @@ -0,0 +1,898 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * + * ST-Ericsson MCDE frame buffer driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/fb.h> +#include <linux/mm.h> +#include <linux/dma-mapping.h> + +#include <linux/hwmem.h> +#include <linux/io.h> + +#include <linux/console.h> + +#include <video/mcde_fb.h> + +#define MCDE_FB_BPP_MAX 16 +#define MCDE_FB_VXRES_MAX 1920 +#define MCDE_FB_VYRES_MAX 2160 + +static struct fb_ops fb_ops; + +struct pix_fmt_info { + enum mcde_ovly_pix_fmt pix_fmt; + + u32 bpp; + struct fb_bitfield r; + struct fb_bitfield g; + struct fb_bitfield b; + struct fb_bitfield a; + u32 nonstd; +}; + +struct pix_fmt_info pix_fmt_map[] = { + { + .pix_fmt = MCDE_OVLYPIXFMT_RGB565, + .bpp = 16, + .r = { .offset = 11, .length = 5 }, + .g = { .offset = 5, .length = 6 }, + .b = { .offset = 0, .length = 5 }, + }, { + .pix_fmt = MCDE_OVLYPIXFMT_RGBA5551, + .bpp = 16, + .r = { .offset = 11, .length = 5 }, + .g = { .offset = 6, .length = 5 }, + .b = { .offset = 1, .length = 5 }, + .a = { .offset = 0, .length = 1 }, + }, { + .pix_fmt = MCDE_OVLYPIXFMT_RGBA4444, + .bpp = 16, + .r = { .offset = 12, .length = 4 }, + .g = { .offset = 8, .length = 4 }, + .b = { .offset = 4, .length = 4 }, + .a = { .offset = 0, .length = 4 }, + }, { + .pix_fmt = MCDE_OVLYPIXFMT_YCbCr422, + .bpp = 16, + .nonstd = MCDE_OVLYPIXFMT_YCbCr422, + }, { + .pix_fmt = MCDE_OVLYPIXFMT_RGB888, + .bpp = 24, + .r = { .offset = 16, .length = 8 }, + .g = { .offset = 8, .length = 8 }, + .b = { .offset = 0, .length = 8 }, + }, { + .pix_fmt = MCDE_OVLYPIXFMT_RGBA8888, + .bpp = 32, + .r = { .offset = 16, .length = 8 }, + .g = { .offset = 8, .length = 8 }, + .b = { .offset = 0, .length = 8 }, + .a = { .offset = 24, .length = 8 }, + }, { + .pix_fmt = MCDE_OVLYPIXFMT_RGBX8888, + .bpp = 32, + .r = { .offset = 16, .length = 8 }, + .g = { .offset = 8, .length = 8 }, + .b = { .offset = 0, .length = 8 }, + } + +}; + +static struct platform_device mcde_fb_device = { + .name = "mcde_fb", + .id = -1, +}; + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void early_suspend(struct early_suspend *data) +{ + int i; + struct mcde_fb *mfb = + container_of(data, struct mcde_fb, early_suspend); + + console_lock(); + for (i = 0; i < mfb->num_ovlys; i++) { + if (mfb->ovlys[i] && mfb->ovlys[i]->ddev && + (mfb->ovlys[i]->ddev->stay_alive == false)) + mcde_dss_disable_display(mfb->ovlys[i]->ddev); + } + console_unlock(); +} + +static void late_resume(struct early_suspend *data) +{ + int i; + struct mcde_fb *mfb = + container_of(data, struct mcde_fb, early_suspend); + + console_lock(); + for (i = 0; i < mfb->num_ovlys; i++) { + if (mfb->ovlys[i]) { + struct mcde_overlay *ovly = mfb->ovlys[i]; + (void) mcde_dss_enable_display(ovly->ddev); + } + } + console_unlock(); +} +#endif + +/* Helpers */ + +static struct pix_fmt_info *find_pix_fmt_info(enum mcde_ovly_pix_fmt pix_fmt) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pix_fmt_map); i++) { + if (pix_fmt_map[i].pix_fmt == pix_fmt) + return &pix_fmt_map[i]; + } + return NULL; +} + +static bool bitfield_cmp(struct fb_bitfield *bf1, struct fb_bitfield *bf2) +{ + return bf1->offset == bf2->offset && + bf1->length == bf2->length && + bf1->msb_right == bf2->msb_right; +} + +static struct pix_fmt_info *var_to_pix_fmt_info(struct fb_var_screeninfo *var) +{ + int i; + struct pix_fmt_info *info; + + if (var->nonstd) + return find_pix_fmt_info(var->nonstd); + + for (i = 0; i < ARRAY_SIZE(pix_fmt_map); i++) { + info = &pix_fmt_map[i]; + if (info->bpp == var->bits_per_pixel && + bitfield_cmp(&info->r, &var->red) && + bitfield_cmp(&info->g, &var->green) && + bitfield_cmp(&info->b, &var->blue) && + bitfield_cmp(&info->a, &var->transp)) + return info; + } + + for (i = 0; i < ARRAY_SIZE(pix_fmt_map); i++) { + info = &pix_fmt_map[i]; + if (var->bits_per_pixel == info->bpp) + return info; + } + + return NULL; +} + +static void pix_fmt_info_to_var(struct pix_fmt_info *pix_fmt_info, + struct fb_var_screeninfo *var) +{ + var->bits_per_pixel = pix_fmt_info->bpp; + var->nonstd = pix_fmt_info->nonstd; + var->red = pix_fmt_info->r; + var->green = pix_fmt_info->g; + var->blue = pix_fmt_info->b; + var->transp = pix_fmt_info->a; +} + +static int init_var_fmt(struct fb_var_screeninfo *var, + u16 w, u16 h, u16 vw, u16 vh, enum mcde_ovly_pix_fmt pix_fmt, + u32 rotate) +{ + struct pix_fmt_info *info; + + info = find_pix_fmt_info(pix_fmt); + if (!info) + return -EINVAL; + + var->bits_per_pixel = info->bpp; + var->nonstd = info->nonstd; + var->red = info->r; + var->green = info->g; + var->blue = info->b; + var->transp = info->a; + var->grayscale = false; + + var->xres = w; + var->yres = h; + var->xres_virtual = vw; + var->yres_virtual = vh; + var->xoffset = 0; + var->yoffset = 0; + var->activate = FB_ACTIVATE_NOW; + var->rotate = rotate; + + return 0; +}; + +static int reallocate_fb_mem(struct fb_info *fbi, u32 size) +{ + struct mcde_fb *mfb = to_mcde_fb(fbi); + void *vaddr; + struct hwmem_alloc *alloc; + struct hwmem_mem_chunk mem_chunk; + size_t num_mem_chunks = 1; + int name; + + size = PAGE_ALIGN(size); + + if (size == fbi->screen_size) + return 0; + +/* TODO: Remove once hwmem has support for defragmentation */ +#ifdef CONFIG_MCDE_FB_AVOID_REALLOC + if (!mfb->alloc) { + u32 old_size = size; + + size = MCDE_FB_BPP_MAX / 8 * MCDE_FB_VXRES_MAX * + MCDE_FB_VYRES_MAX; +#endif + + alloc = hwmem_alloc(size, HWMEM_ALLOC_HINT_WRITE_COMBINE | + HWMEM_ALLOC_HINT_UNCACHED, + (HWMEM_ACCESS_READ | HWMEM_ACCESS_WRITE | + HWMEM_ACCESS_IMPORT), + HWMEM_MEM_CONTIGUOUS_SYS); + if (IS_ERR(alloc)) + return PTR_ERR(alloc); + + name = hwmem_get_name(alloc); + if (name < 0) { + hwmem_release(alloc); + return name; + } + + if (mfb->alloc) { + hwmem_kunmap(mfb->alloc); + hwmem_unpin(mfb->alloc); + hwmem_release(mfb->alloc); + } + + (void)hwmem_pin(alloc, &mem_chunk, &num_mem_chunks); + + vaddr = hwmem_kmap(alloc); + if (vaddr == NULL) { + hwmem_unpin(alloc); + hwmem_release(alloc); + return -ENOMEM; + } + + mfb->alloc = alloc; + mfb->alloc_name = name; + + fbi->screen_base = vaddr; + fbi->fix.smem_start = mem_chunk.paddr; + +#ifdef CONFIG_MCDE_FB_AVOID_REALLOC + size = old_size; + } +#endif + + fbi->screen_size = size; + fbi->fix.smem_len = size; + + return 0; +} + +static void free_fb_mem(struct fb_info *fbi) +{ + struct mcde_fb *mfb = to_mcde_fb(fbi); + + if (mfb->alloc) { + hwmem_kunmap(mfb->alloc); + hwmem_unpin(mfb->alloc); + hwmem_release(mfb->alloc); + mfb->alloc = NULL; + mfb->alloc_name = 0; + + fbi->fix.smem_start = 0; + fbi->fix.smem_len = 0; + fbi->screen_base = 0; + fbi->screen_size = 0; + } +} + +static void init_fb(struct fb_info *fbi) +{ + struct mcde_fb *mfb = to_mcde_fb(fbi); + + strlcpy(fbi->fix.id, "mcde_fb", sizeof(fbi->fix.id)); + fbi->fix.type = FB_TYPE_PACKED_PIXELS; + fbi->fix.visual = FB_VISUAL_DIRECTCOLOR; + fbi->fix.xpanstep = 1; + fbi->fix.ypanstep = 1; + fbi->flags = FBINFO_HWACCEL_DISABLED; + fbi->fbops = &fb_ops; + fbi->pseudo_palette = &mfb->pseudo_palette[0]; +} + +static void get_ovly_info(struct fb_info *fbi, struct mcde_overlay *ovly, + struct mcde_overlay_info *info) +{ + struct mcde_fb *mfb = to_mcde_fb(fbi); + + memset(info, 0, sizeof(*info)); + info->paddr = fbi->fix.smem_start + + fbi->fix.line_length * fbi->var.yoffset; + info->vaddr = (u32 *)(fbi->screen_base + + fbi->fix.line_length * fbi->var.yoffset); + /* TODO: move mem check to check_var/pan_display */ + if (info->paddr + fbi->fix.line_length * fbi->var.yres > + fbi->fix.smem_start + fbi->fix.smem_len) { + info->paddr = fbi->fix.smem_start; + info->vaddr = (u32 *)fbi->screen_base; + } + info->fmt = mfb->pix_fmt; + info->stride = fbi->fix.line_length; + if (ovly) { + info->src_x = ovly->info.src_x; + info->src_y = ovly->info.src_y; + info->dst_x = ovly->info.dst_x; + info->dst_y = ovly->info.dst_y; + info->dst_z = 1; + } else { + info->src_x = 0; + info->src_y = 0; + info->dst_x = 0; + info->dst_y = 0; + info->dst_z = 1; + } + info->w = fbi->var.xres; + info->h = fbi->var.yres; + info->dirty.x = 0; + info->dirty.y = 0; + info->dirty.w = fbi->var.xres; + info->dirty.h = fbi->var.yres; +} + +void vmode_to_var(struct mcde_video_mode *video_mode, + struct fb_var_screeninfo *var) +{ + /* TODO: use only 1 vbp and 1 vfp */ + var->xres = video_mode->xres; + var->yres = video_mode->yres; + var->pixclock = video_mode->pixclock; + var->upper_margin = video_mode->vbp; + var->lower_margin = video_mode->vfp; + var->vsync_len = video_mode->vsw; + var->left_margin = video_mode->hbp; + var->right_margin = video_mode->hfp; + var->hsync_len = video_mode->hsw; + var->vmode &= ~FB_VMODE_INTERLACED; + var->vmode |= video_mode->interlaced ? + FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED; +} + +void var_to_vmode(struct fb_var_screeninfo *var, + struct mcde_video_mode *video_mode) +{ + video_mode->xres = var->xres; + video_mode->yres = var->yres; + video_mode->pixclock = var->pixclock; + video_mode->vbp = var->upper_margin; + video_mode->vfp = var->lower_margin; + video_mode->vsw = var->vsync_len; + video_mode->hbp = var->left_margin; + video_mode->hfp = var->right_margin; + video_mode->hsw = var->hsync_len; + video_mode->interlaced = (var->vmode & FB_VMODE_INTERLACED) == + FB_VMODE_INTERLACED; +} + +enum mcde_display_rotation var_to_rotation(struct fb_var_screeninfo *var) +{ + enum mcde_display_rotation rot; + + switch (var->rotate) { + case FB_ROTATE_UR: + rot = MCDE_DISPLAY_ROT_0; + break; + case FB_ROTATE_CW: + rot = MCDE_DISPLAY_ROT_90_CW; + break; + case FB_ROTATE_UD: + rot = MCDE_DISPLAY_ROT_180_CW; + break; + case FB_ROTATE_CCW: + rot = MCDE_DISPLAY_ROT_90_CCW; + break; + default: + rot = MCDE_DISPLAY_ROT_0; + break; + } + dev_vdbg(&mcde_fb_device.dev, "var_rot: %d -> mcde_rot: %d\n", + var->rotate, rot); + return rot; +} + +static struct mcde_display_device *fb_to_display(struct fb_info *fbi) +{ + int i; + struct mcde_fb *mfb = to_mcde_fb(fbi); + + for (i = 0; i < mfb->num_ovlys; i++) { + if (mfb->ovlys[i]) + return mfb->ovlys[i]->ddev; + } + return NULL; +} + +static int check_var(struct fb_var_screeninfo *var, struct fb_info *fbi, + struct mcde_display_device *ddev) +{ + int ret; + u16 w = -1, h = -1; + struct mcde_video_mode vmode; + struct pix_fmt_info *fmtinfo; + + /* TODO: check sizes/offsets/memory validity */ + + /* Device physical size */ + mcde_dss_get_physical_size(ddev, &w, &h); + var->width = w; + var->height = h; + + /* Rotation */ + if (var->rotate > 3) { + dev_info(&(ddev->dev), "check_var failed var->rotate\n"); + return -EINVAL; + } + + /* Video mode */ + var_to_vmode(var, &vmode); + ret = mcde_dss_try_video_mode(ddev, &vmode); + if (ret < 0) { + dev_vdbg(&(ddev->dev), "check_var failed " + "mcde_dss_try_video_mode with size = %x\n", ret); + return ret; + } + vmode_to_var(&vmode, var); + + /* Pixel format */ + fmtinfo = var_to_pix_fmt_info(var); + if (!fmtinfo) { + dev_vdbg(&(ddev->dev), "check_var failed fmtinfo\n"); + return -EINVAL; + } + pix_fmt_info_to_var(fmtinfo, var); + + /* Not used */ + var->grayscale = 0; + var->sync = 0; + + return 0; +} + +static int apply_var(struct fb_info *fbi, struct mcde_display_device *ddev) +{ + int ret, i; + struct mcde_fb *mfb = to_mcde_fb(fbi); + struct fb_var_screeninfo *var; + struct mcde_video_mode vmode; + struct pix_fmt_info *fmt; + u32 line_len, size; + + if (!ddev) + return -ENODEV; + + dev_vdbg(&(ddev->dev), "%s\n", __func__); + + var = &fbi->var; + + ddev->check_transparency = 60; + + /* Reallocate memory */ + line_len = (fbi->var.bits_per_pixel * var->xres_virtual) / 8; + line_len = ALIGN(line_len, MCDE_BUF_LINE_ALIGMENT); + size = line_len * var->yres_virtual; + ret = reallocate_fb_mem(fbi, size); + if (ret) { + dev_vdbg(&(ddev->dev), "apply_var failed with" + "reallocate mem with size = %d\n", size); + return ret; + } + fbi->fix.line_length = line_len; + + if (ddev->fictive) + goto apply_var_end; + + /* Apply pixel format */ + fmt = var_to_pix_fmt_info(var); + mfb->pix_fmt = fmt->pix_fmt; + + /* Apply rotation */ + mcde_dss_set_rotation(ddev, var_to_rotation(var)); + /* Apply video mode */ + memset(&vmode, 0, sizeof(struct mcde_video_mode)); + var_to_vmode(var, &vmode); + ret = mcde_dss_set_video_mode(ddev, &vmode); + if (ret) + return ret; + + mcde_dss_apply_channel(ddev); + + /* Apply overlay info */ + for (i = 0; i < mfb->num_ovlys; i++) { + struct mcde_overlay *ovly = mfb->ovlys[i]; + struct mcde_overlay_info info; + int num_buffers; + + get_ovly_info(fbi, ovly, &info); + (void) mcde_dss_apply_overlay(ovly, &info); + + num_buffers = var->yres_virtual / var->yres; + mcde_dss_update_overlay(ovly, num_buffers == 3); + } + +apply_var_end: + return 0; +} + +/* FB ops */ + +static int mcde_fb_open(struct fb_info *fbi, int user) +{ + dev_vdbg(fbi->dev, "%s\n", __func__); + return 0; +} + +static int mcde_fb_release(struct fb_info *fbi, int user) +{ + dev_vdbg(fbi->dev, "%s\n", __func__); + return 0; +} + +static int mcde_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) +{ + struct mcde_display_device *ddev = fb_to_display(fbi); + + dev_vdbg(fbi->dev, "%s\n", __func__); + + if (!ddev) { + printk(KERN_ERR "mcde_fb_check_var failed !ddev\n"); + return -ENODEV; + } + + return check_var(var, fbi, ddev); +} + +static int mcde_fb_set_par(struct fb_info *fbi) +{ + struct mcde_fb *mfb = to_mcde_fb(fbi); + struct mcde_display_device *ddev = fb_to_display(fbi); + dev_vdbg(fbi->dev, "%s\n", __func__); + + if (mfb->ovlys[0]->state == NULL && + ddev->fictive == false) { + printk(KERN_INFO "%s() - Enable fb %p\n", + __func__, + mfb->ovlys[0]); + mcde_dss_enable_overlay(mfb->ovlys[0]); + } + + return apply_var(fbi, ddev); +} + +static int mcde_fb_blank(int blank, struct fb_info *fbi) +{ + int ret = 0; + struct mcde_display_device *ddev = fb_to_display(fbi); + + dev_vdbg(fbi->dev, "%s\n", __func__); + + if (ddev->fictive) + goto mcde_fb_blank_end; + + switch (blank) { + case FB_BLANK_NORMAL: + break; + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + mcde_dss_disable_display(ddev); + break; + case FB_BLANK_UNBLANK: + ret = mcde_dss_enable_display(ddev); + break; + default: + ret = -EINVAL; + } + +mcde_fb_blank_end: + return ret; +} + +static int mcde_fb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *fbi) +{ + dev_vdbg(fbi->dev, "%s\n", __func__); + + if (var->xoffset == fbi->var.xoffset && + var->yoffset == fbi->var.yoffset) + return 0; + + fbi->var.xoffset = var->xoffset; + fbi->var.yoffset = var->yoffset; + return apply_var(fbi, fb_to_display(fbi)); +} + +static void mcde_fb_rotate(struct fb_info *fbi, int rotate) +{ + dev_vdbg(fbi->dev, "%s\n", __func__); +} + +static int mcde_fb_ioctl(struct fb_info *fbi, unsigned int cmd, + unsigned long arg) +{ + struct mcde_fb *mfb = to_mcde_fb(fbi); + + if (cmd == MCDE_GET_BUFFER_NAME_IOC) + return mfb->alloc_name; + + return -EINVAL; +} + +static int mcde_fb_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, unsigned int transp, + struct fb_info *fbi) +{ + dev_vdbg(fbi->dev, "%s\n", __func__); + + if (regno >= 256) + return 1; + + if (regno < 17) { + u32 pseudo_val; + u32 r, g, b; + + if (fbi->var.bits_per_pixel > 16) { + r = red >> 8; + g = green >> 8; + b = blue >> 8; + } else if (fbi->var.bits_per_pixel == 16) { + r = red >> (3 + 8); + g = green >> (2 + 8); + b = blue >> (3 + 8); + } else if (fbi->var.bits_per_pixel == 15) { + r = red >> (3 + 8); + g = green >> (3 + 8); + b = blue >> (3 + 8); + } else + r = b = g = (regno & 15); + pseudo_val = r << fbi->var.red.offset; + pseudo_val |= g << fbi->var.green.offset; + pseudo_val |= b << fbi->var.blue.offset; + + ((u32 *)fbi->pseudo_palette)[regno] = pseudo_val; + } + + return 0; +} + +static int mcde_fb_setcmap(struct fb_cmap *cmap, struct fb_info *fbi) +{ + dev_vdbg(fbi->dev, "%s\n", __func__); + + /*Nothing to see here, move along*/ + return 0; +} + +static struct fb_ops fb_ops = { + /* creg, cmap */ + .owner = THIS_MODULE, + .fb_open = mcde_fb_open, + .fb_release = mcde_fb_release, + .fb_read = fb_sys_read, + .fb_write = fb_sys_write, + .fb_fillrect = sys_fillrect, + .fb_copyarea = sys_copyarea, + .fb_imageblit = sys_imageblit, + .fb_check_var = mcde_fb_check_var, + .fb_set_par = mcde_fb_set_par, + .fb_blank = mcde_fb_blank, + .fb_pan_display = mcde_fb_pan_display, + .fb_rotate = mcde_fb_rotate, + .fb_ioctl = mcde_fb_ioctl, + .fb_setcolreg = mcde_fb_setcolreg, + .fb_setcmap = mcde_fb_setcmap, +}; + +/* FB driver */ + +struct fb_info *mcde_fb_create(struct mcde_display_device *ddev, + u16 w, u16 h, u16 vw, u16 vh, enum mcde_ovly_pix_fmt pix_fmt, + u32 rotate) +{ + int ret = 0; + struct fb_info *fbi; + struct mcde_fb *mfb; + struct mcde_overlay *ovly = NULL; + struct mcde_overlay_info ovly_info; + + dev_vdbg(&ddev->dev, "%s\n", __func__); + if (!ddev->initialized) { + dev_warn(&ddev->dev, "%s: Device not initialized\n", __func__); + return ERR_PTR(-EINVAL); + } + + /* Init fb */ + fbi = framebuffer_alloc(sizeof(struct mcde_fb), &mcde_fb_device.dev); + if (fbi == NULL) { + ret = -ENOMEM; + goto fb_alloc_failed; + } + init_fb(fbi); + mfb = to_mcde_fb(fbi); + + if (ddev->fictive == false) { + ret = mcde_dss_open_channel(ddev); + if (ret) + goto channel_open_failed; + + ret = mcde_dss_enable_display(ddev); + if (ret) + goto display_enable_failed; + } + + /* Prepare var and allocate frame buffer memory */ + init_var_fmt(&fbi->var, w, h, vw, vh, pix_fmt, rotate); + check_var(&fbi->var, fbi, ddev); + ret = apply_var(fbi, ddev); + if (ret) + goto apply_var_failed; + + if (ddev->fictive == false) + mcde_dss_set_pixel_format(ddev, ddev->port->pixel_format); + + /* Setup overlay */ + get_ovly_info(fbi, NULL, &ovly_info); + ovly = mcde_dss_create_overlay(ddev, &ovly_info); + if (!ovly) { + ret = PTR_ERR(ovly); + goto ovly_alloc_failed; + } + mfb->ovlys[0] = ovly; + mfb->num_ovlys = 1; + + if (ddev->fictive == false) { + ret = mcde_dss_enable_overlay(ovly); + if (ret) + goto ovly_enable_failed; + } + + mfb->id = ddev->id; + + /* Register framebuffer */ + ret = register_framebuffer(fbi); + if (ret) + goto fb_register_failed; + + ret = fb_alloc_cmap(&fbi->cmap, 256, 0); + if (ret) + dev_warn(&ddev->dev, "%s: Allocate color map memory failed!\n", + __func__); + + ddev->fbi = fbi; + +#ifdef CONFIG_HAS_EARLYSUSPEND + if (ddev->fictive == false) { + mfb->early_suspend.level = + EARLY_SUSPEND_LEVEL_DISABLE_FB; + mfb->early_suspend.suspend = early_suspend; + mfb->early_suspend.resume = late_resume; + register_early_suspend(&mfb->early_suspend); + } +#endif + + goto out; +fb_register_failed: + mcde_dss_disable_overlay(ovly); +ovly_enable_failed: + mcde_dss_destroy_overlay(ovly); +ovly_alloc_failed: + free_fb_mem(fbi); +apply_var_failed: + mcde_dss_disable_display(ddev); +display_enable_failed: + mcde_dss_close_channel(ddev); +channel_open_failed: + framebuffer_release(fbi); + fbi = NULL; +fb_alloc_failed: +out: + return ret ? ERR_PTR(ret) : fbi; +} +EXPORT_SYMBOL(mcde_fb_create); + +int mcde_fb_attach_overlay(struct fb_info *fb_info, struct mcde_overlay *ovl) +{ + /* TODO: Attach extra overlay targets */ + return -EINVAL; +} + +void mcde_fb_destroy(struct mcde_display_device *dev) +{ + struct mcde_fb *mfb; + int i; + + dev_vdbg(&dev->dev, "%s\n", __func__); + + if (dev->fictive == false) { + mcde_dss_disable_display(dev); + mcde_dss_close_channel(dev); + } + + mfb = to_mcde_fb(dev->fbi); + for (i = 0; i < mfb->num_ovlys; i++) { + if (mfb->ovlys[i]) + mcde_dss_destroy_overlay(mfb->ovlys[i]); + } + +#ifdef CONFIG_HAS_EARLYSUSPEND + if (dev->fictive == false) + unregister_early_suspend(&mfb->early_suspend); +#endif + fb_dealloc_cmap(&dev->fbi->cmap); + + unregister_framebuffer(dev->fbi); + free_fb_mem(dev->fbi); + framebuffer_release(dev->fbi); + dev->fbi = NULL; +} + +/* Overlay fbs' platform device */ +static int mcde_fb_probe(struct platform_device *pdev) +{ + return 0; +} + +static int mcde_fb_remove(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver mcde_fb_driver = { + .probe = mcde_fb_probe, + .remove = mcde_fb_remove, + .driver = { + .name = "mcde_fb", + .owner = THIS_MODULE, + }, +}; + +/* MCDE fb init */ + +int __init mcde_fb_init(void) +{ + int ret; + + ret = platform_driver_register(&mcde_fb_driver); + if (ret) + goto fb_driver_failed; + ret = platform_device_register(&mcde_fb_device); + if (ret) + goto fb_device_failed; + + goto out; +fb_device_failed: + platform_driver_unregister(&mcde_fb_driver); +fb_driver_failed: +out: + return ret; +} + +void mcde_fb_exit(void) +{ + platform_device_unregister(&mcde_fb_device); + platform_driver_unregister(&mcde_fb_driver); +} diff --git a/drivers/video/mcde/mcde_hw.c b/drivers/video/mcde/mcde_hw.c new file mode 100644 index 00000000000..6e846e60f47 --- /dev/null +++ b/drivers/video/mcde/mcde_hw.c @@ -0,0 +1,3709 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson MCDE base driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/export.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/err.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/regulator/consumer.h> +#include <linux/clk.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/workqueue.h> + +#include <linux/mfd/dbx500-prcmu.h> + +#include <video/mcde.h> +#include "dsilink_regs.h" +#include "mcde_regs.h" +#include "mcde_debugfs.h" + + +/* MCDE channel states + * + * Allowed state transitions: + * IDLE <-> SUSPEND + * IDLE <-> DSI_READ + * IDLE <-> DSI_WRITE + * IDLE -> SETUP -> (WAIT_TE ->) RUNNING -> STOPPING1 -> STOPPING2 -> IDLE + * WAIT_TE -> STOPPED (for missing TE to allow re-enable) + */ +enum chnl_state { + CHNLSTATE_SUSPEND, /* HW in suspended mode, initial state */ + CHNLSTATE_IDLE, /* Channel aquired, but not running, FLOEN==0 */ + CHNLSTATE_DSI_READ, /* Executing DSI read */ + CHNLSTATE_DSI_WRITE, /* Executing DSI write */ + CHNLSTATE_SETUP, /* Channel register setup to prepare for running */ + CHNLSTATE_WAIT_TE, /* Waiting for BTA or external TE */ + CHNLSTATE_RUNNING, /* Update started, FLOEN=1, FLOEN==1 */ + CHNLSTATE_STOPPING, /* Stopping, FLOEN=0, FLOEN==1, awaiting VCMP */ + CHNLSTATE_STOPPED, /* Stopped, after VCMP, FLOEN==0|1 */ +}; + +enum dsi_lane_status { + DSI_LANE_STATE_START = 0x00, + DSI_LANE_STATE_IDLE = 0x01, + DSI_LANE_STATE_WRITE = 0x02, + DSI_LANE_STATE_ULPM = 0x03, +}; + +static int set_channel_state_atomic(struct mcde_chnl_state *chnl, + enum chnl_state state); +static int set_channel_state_sync(struct mcde_chnl_state *chnl, + enum chnl_state state); +static void stop_channel(struct mcde_chnl_state *chnl); +static int _mcde_chnl_enable(struct mcde_chnl_state *chnl); +static int _mcde_chnl_apply(struct mcde_chnl_state *chnl); +static void disable_flow(struct mcde_chnl_state *chnl); +static void enable_flow(struct mcde_chnl_state *chnl); +static void do_softwaretrig(struct mcde_chnl_state *chnl); +static void dsi_te_poll_req(struct mcde_chnl_state *chnl); +static void dsi_te_poll_set_timer(struct mcde_chnl_state *chnl, + unsigned int timeout); +static void dsi_te_timer_function(unsigned long value); +static int wait_for_vcmp(struct mcde_chnl_state *chnl); +static int probe_hw(struct platform_device *pdev); +static void wait_for_flow_disabled(struct mcde_chnl_state *chnl); + +#define OVLY_TIMEOUT 100 +#define CHNL_TIMEOUT 100 +#define FLOW_STOP_TIMEOUT 20 +#define SCREEN_PPL_HIGH 1280 +#define SCREEN_PPL_CEA2 720 +#define SCREEN_LPF_CEA2 480 +#define DSI_DELAY0_CEA2_ADD 10 + +#define MCDE_SLEEP_WATCHDOG 500 +#define DSI_TE_NO_ANSWER_TIMEOUT_INIT 2500 +#define DSI_TE_NO_ANSWER_TIMEOUT 250 +#define DSI_WAIT_FOR_ULPM_STATE_MS 1 +#define DSI_ULPM_STATE_NBR_OF_RETRIES 10 +#define DSI_READ_TIMEOUT 200 +#define DSI_WRITE_CMD_TIMEOUT 1000 +#define DSI_READ_DELAY 5 +#define DSI_READ_NBR_OF_RETRIES 2 +#define MCDE_FLOWEN_MAX_TRIAL 60 +#define DSI_RESET_SW 0x7 + +#define MCDE_VERSION_4_1_3 0x04010300 +#define MCDE_VERSION_4_0_4 0x04000400 +#define MCDE_VERSION_3_0_8 0x03000800 +#define MCDE_VERSION_3_0_5 0x03000500 +#define MCDE_VERSION_1_0_4 0x01000400 + +#define CLK_MCDE "mcde" +#define CLK_DPI "lcd" + +static u8 *mcdeio; +static u8 **dsiio; +static struct platform_device *mcde_dev; +static u8 num_dsilinks; +static u8 num_channels; +static u8 num_overlays; +static int mcde_irq; +static u32 input_fifo_size; +static u32 output_fifo_ab_size; +static u32 output_fifo_c0c1_size; + +static struct regulator *regulator_vana; +static struct regulator *regulator_mcde_epod; +static struct regulator *regulator_esram_epod; +static struct clk *clock_mcde; + +/* TODO remove when all platforms support dsilp and dsihs clocks */ +static struct clk *clock_dsi; +static struct clk *clock_dsi_lp; + +static u8 mcde_is_enabled; +static struct delayed_work hw_timeout_work; +static u8 dsi_pll_is_enabled; +static u8 dsi_ifc_is_supported; +static u8 dsi_use_clk_framework; +static u32 mcde_clk_rate; /* In Hz */ + +static struct mutex mcde_hw_lock; +static inline void mcde_lock(const char *func, int line) +{ + mutex_lock(&mcde_hw_lock); + dev_vdbg(&mcde_dev->dev, "Enter MCDE: %s:%d\n", func, line); +} + +static inline void mcde_unlock(const char *func, int line) +{ + dev_vdbg(&mcde_dev->dev, "Exit MCDE: %s:%d\n", func, line); + mutex_unlock(&mcde_hw_lock); +} + +static inline bool mcde_trylock(const char *func, int line) +{ + bool locked = mutex_trylock(&mcde_hw_lock) == 1; + if (locked) + dev_vdbg(&mcde_dev->dev, "Enter MCDE: %s:%d\n", func, line); + return locked; +} + +static u8 mcde_dynamic_power_management = true; + +static inline u32 dsi_rreg(int i, u32 reg) +{ + return readl(dsiio[i] + reg); +} +static inline void dsi_wreg(int i, u32 reg, u32 val) +{ + writel(val, dsiio[i] + reg); +} + +#define dsi_rfld(__i, __reg, __fld) \ +({ \ + const u32 mask = __reg##_##__fld##_MASK; \ + const u32 shift = __reg##_##__fld##_SHIFT; \ + ((dsi_rreg(__i, __reg) & mask) >> shift); \ +}) + +#define dsi_wfld(__i, __reg, __fld, __val) \ +({ \ + const u32 mask = __reg##_##__fld##_MASK; \ + const u32 shift = __reg##_##__fld##_SHIFT; \ + const u32 oldval = dsi_rreg(__i, __reg); \ + const u32 newval = ((__val) << shift); \ + dsi_wreg(__i, __reg, (oldval & ~mask) | (newval & mask)); \ +}) + +static inline u32 mcde_rreg(u32 reg) +{ + return readl(mcdeio + reg); +} +static inline void mcde_wreg(u32 reg, u32 val) +{ + writel(val, mcdeio + reg); +} + + +#define mcde_rfld(__reg, __fld) \ +({ \ + const u32 mask = __reg##_##__fld##_MASK; \ + const u32 shift = __reg##_##__fld##_SHIFT; \ + ((mcde_rreg(__reg) & mask) >> shift); \ +}) + +#define mcde_wfld(__reg, __fld, __val) \ +({ \ + const u32 mask = __reg##_##__fld##_MASK; \ + const u32 shift = __reg##_##__fld##_SHIFT; \ + const u32 oldval = mcde_rreg(__reg); \ + const u32 newval = ((__val) << shift); \ + mcde_wreg(__reg, (oldval & ~mask) | (newval & mask)); \ +}) + +struct ovly_regs { + bool enabled; + bool dirty; + bool dirty_buf; + + u8 ch_id; + u32 baseaddress0; + u32 baseaddress1; + u8 bits_per_pixel; + u8 bpp; + bool bgr; + bool bebo; + bool opq; + u8 col_conv; + u8 alpha_source; + u8 alpha_value; + u8 pixoff; + u16 ppl; + u16 lpf; + u16 cropx; + u16 cropy; + u16 xpos; + u16 ypos; + u8 z; +}; + +struct mcde_ovly_state { + bool inuse; + u8 idx; /* MCDE overlay index */ + struct mcde_chnl_state *chnl; /* Owner channel */ + bool dirty; + bool dirty_buf; + + /* Staged settings */ + u32 paddr; + u16 stride; + enum mcde_ovly_pix_fmt pix_fmt; + + u16 src_x; + u16 src_y; + u16 dst_x; + u16 dst_y; + u16 dst_z; + u16 w; + u16 h; + + u8 alpha_source; + u8 alpha_value; + + /* Applied settings */ + struct ovly_regs regs; +}; + +static struct mcde_ovly_state *overlays; + +struct chnl_regs { + bool dirty; + + bool floen; + u16 x; + u16 y; + u16 ppl; + u16 lpf; + u8 bpp; + bool internal_clk; /* CLKTYPE field */ + u16 pcd; + u8 clksel; + u8 cdwin; + u16 (*map_r)(u8); + u16 (*map_g)(u8); + u16 (*map_b)(u8); + bool palette_enable; + bool bcd; + bool synchronized_update; + bool roten; + u8 rotdir; + u32 rotbuf1; + u32 rotbuf2; + + /* Blending */ + u8 blend_ctrl; + bool blend_en; + u8 alpha_blend; + + /* DSI */ + u8 dsipacking; +}; + +struct col_regs { + bool dirty; + + u16 y_red; + u16 y_green; + u16 y_blue; + u16 cb_red; + u16 cb_green; + u16 cb_blue; + u16 cr_red; + u16 cr_green; + u16 cr_blue; + u16 off_y; + u16 off_cb; + u16 off_cr; +}; + +struct tv_regs { + bool dirty; + + u16 dho; /* TV mode: left border width; destination horizontal offset */ + /* LCD MODE: horizontal back porch */ + u16 alw; /* TV mode: right border width */ + /* LCD mode: horizontal front porch */ + u16 hsw; /* horizontal synch width */ + u16 dvo; /* TV mode: top border width; destination horizontal offset */ + /* LCD MODE: vertical back porch */ + u16 bsl; /* TV mode: bottom border width; blanking start line */ + /* LCD MODE: vertical front porch */ + /* field 1 */ + u16 bel1; /* TV mode: field total vertical blanking lines */ + /* LCD mode: vertical sync width */ + u16 fsl1; /* field vbp */ + /* field 2 */ + u16 bel2; + u16 fsl2; + u8 tv_mode; + bool sel_mode_tv; + bool inv_clk; + bool interlaced_en; + u32 lcdtim1; +}; + +struct mcde_chnl_state { + bool enabled; + bool reserved; + enum mcde_chnl id; + enum mcde_fifo fifo; + struct mcde_port port; + struct mcde_ovly_state *ovly0; + struct mcde_ovly_state *ovly1; + enum chnl_state state; + wait_queue_head_t state_waitq; + wait_queue_head_t vcmp_waitq; + atomic_t vcmp_cnt; + struct timer_list dsi_te_timer; + struct clk *clk_dsi_lp; + struct clk *clk_dsi_hs; + struct clk *clk_dpi; + + enum mcde_display_power_mode power_mode; + + /* Staged settings */ + u16 (*map_r)(u8); + u16 (*map_g)(u8); + u16 (*map_b)(u8); + bool palette_enable; + bool synchronized_update; + struct mcde_video_mode vmode; + enum mcde_display_rotation rotation; + u32 rotbuf1; + u32 rotbuf2; + + struct mcde_col_transform rgb_2_ycbcr; + struct mcde_col_transform ycbcr_2_rgb; + struct mcde_col_transform *transform; + + /* Blending */ + u8 blend_ctrl; + bool blend_en; + u8 alpha_blend; + + /* Applied settings */ + struct chnl_regs regs; + struct col_regs col_regs; + struct tv_regs tv_regs; + + /* an interlaced digital TV signal generates a VCMP per field */ + bool vcmp_per_field; + bool even_vcmp; + + bool formatter_updated; + bool esram_is_enabled; +}; + +static struct mcde_chnl_state *channels; +/* + * Wait for CSM_RUNNING, all data sent for display + */ +static inline void wait_while_dsi_running(int lnk) +{ + u8 counter = DSI_READ_TIMEOUT; + while (dsi_rfld(lnk, DSI_CMD_MODE_STS, CSM_RUNNING) && --counter) { + dev_vdbg(&mcde_dev->dev, + "%s: DSI link %u read running state retry %u times\n" + , __func__, lnk, (DSI_READ_TIMEOUT - counter)); + udelay(DSI_READ_DELAY); + } + WARN_ON(!counter); + if (!counter) + dev_warn(&mcde_dev->dev, + "%s: DSI link %u read timeout!\n", __func__, lnk); +} + +static void enable_clocks_and_power(struct platform_device *pdev) +{ + struct mcde_platform_data *pdata = pdev->dev.platform_data; + + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + /* VANA should be enabled before a DSS hard reset */ + if (regulator_vana) + WARN_ON_ONCE(regulator_enable(regulator_vana)); + + WARN_ON_ONCE(regulator_enable(regulator_mcde_epod)); + + if (!dsi_use_clk_framework) + pdata->platform_set_clocks(); + + WARN_ON_ONCE(clk_enable(clock_mcde)); +} + +static void disable_clocks_and_power(struct platform_device *pdev) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + clk_disable(clock_mcde); + + WARN_ON_ONCE(regulator_disable(regulator_mcde_epod)); + + if (regulator_vana) + WARN_ON_ONCE(regulator_disable(regulator_vana)); +} + +static void update_mcde_registers(void) +{ + struct mcde_platform_data *pdata = mcde_dev->dev.platform_data; + + /* Setup output muxing */ + mcde_wreg(MCDE_CONF0, + MCDE_CONF0_IFIFOCTRLWTRMRKLVL(7) | + MCDE_CONF0_OUTMUX0(pdata->outmux[0]) | + MCDE_CONF0_OUTMUX1(pdata->outmux[1]) | + MCDE_CONF0_OUTMUX2(pdata->outmux[2]) | + MCDE_CONF0_OUTMUX3(pdata->outmux[3]) | + MCDE_CONF0_OUTMUX4(pdata->outmux[4]) | + pdata->syncmux); + + mcde_wfld(MCDE_RISPP, VCMPARIS, 1); + mcde_wfld(MCDE_RISPP, VCMPBRIS, 1); + mcde_wfld(MCDE_RISPP, VCMPC0RIS, 1); + mcde_wfld(MCDE_RISPP, VCMPC1RIS, 1); + + /* Enable channel VCMP interrupts */ + mcde_wreg(MCDE_IMSCPP, + MCDE_IMSCPP_VCMPAIM(true) | + MCDE_IMSCPP_VCMPBIM(true) | + MCDE_IMSCPP_VCMPC0IM(true) | + MCDE_IMSCPP_VCMPC1IM(true)); + + mcde_wreg(MCDE_IMSCCHNL, MCDE_IMSCCHNL_CHNLAIM(0xf)); + mcde_wreg(MCDE_IMSCERR, 0xFFFF01FF); + + /* Setup sync pulse length + * Setting VSPMAX=0 disables the filter and VSYNC + * is generated after VSPMIN mcde cycles + */ + mcde_wreg(MCDE_VSCRC0, + MCDE_VSCRC0_VSPMIN(0) | + MCDE_VSCRC0_VSPMAX(0)); + mcde_wreg(MCDE_VSCRC1, + MCDE_VSCRC1_VSPMIN(1) | + MCDE_VSCRC1_VSPMAX(0xff)); +} + +static void dsi_link_handle_ulpm(struct mcde_port *port, bool enter_ulpm) +{ + u8 link = port->link; + u8 num_data_lanes = port->phy.dsi.num_data_lanes; + u8 nbr_of_retries = 0; + u8 lane_state; + + /* + * The D-PHY protocol specifies the time to leave the ULP mode + * in ms. It will at least take 1 ms to exit ULPM. + * The ULPOUT time value is using number of system clock ticks + * divided by 1000. The system clock for the DSI link is the MCDE + * clock. + */ + dsi_wreg(link, DSI_MCTL_ULPOUT_TIME, + DSI_MCTL_ULPOUT_TIME_CKLANE_ULPOUT_TIME(0x1FF) | + DSI_MCTL_ULPOUT_TIME_DATA_ULPOUT_TIME(0x1FF)); + + dsi_wfld(link, DSI_MCTL_MAIN_EN, DAT1_ULPM_REQ, enter_ulpm); + dsi_wfld(link, DSI_MCTL_MAIN_EN, DAT2_ULPM_REQ, + enter_ulpm && num_data_lanes == 2); + + if (enter_ulpm) + lane_state = DSI_LANE_STATE_ULPM; + else + lane_state = DSI_LANE_STATE_IDLE; + + /* Wait for data lanes to enter ULPM */ + while (dsi_rfld(link, DSI_MCTL_LANE_STS, DATLANE1_STATE) + != lane_state || + (dsi_rfld(link, DSI_MCTL_LANE_STS, DATLANE2_STATE) + != lane_state && + num_data_lanes > 1)) { + mdelay(DSI_WAIT_FOR_ULPM_STATE_MS); + if (nbr_of_retries++ == DSI_ULPM_STATE_NBR_OF_RETRIES) { + dev_warn(&mcde_dev->dev, + "Could not enter correct state=%d (link=%d)!\n", + lane_state, link); + break; + } + } + + dsi_wfld(link, DSI_MCTL_MAIN_EN, CLKLANE_ULPM_REQ, enter_ulpm); + nbr_of_retries = 0; + + /* Wait for clock lane to enter ULPM */ + while (dsi_rfld(link, DSI_MCTL_LANE_STS, CLKLANE_STATE) + != lane_state) { + mdelay(DSI_WAIT_FOR_ULPM_STATE_MS); + if (nbr_of_retries++ == DSI_ULPM_STATE_NBR_OF_RETRIES) { + dev_warn(&mcde_dev->dev, + "Could not enter correct state=%d (link=%d)!\n", + lane_state, link); + break; + } + } +} + +static int dsi_link_enable(struct mcde_chnl_state *chnl) +{ + int ret = 0; + u8 link = chnl->port.link; + + if (dsi_use_clk_framework) { + prcmu_write(DB8500_PRCM_DSI_SW_RESET, DSI_RESET_SW); + WARN_ON_ONCE(clk_enable(chnl->clk_dsi_lp)); + WARN_ON_ONCE(clk_enable(chnl->clk_dsi_hs)); + } else { + WARN_ON_ONCE(clk_enable(clock_dsi)); + WARN_ON_ONCE(clk_enable(clock_dsi_lp)); + + if (!dsi_pll_is_enabled) { + struct mcde_platform_data *pdata = + mcde_dev->dev.platform_data; + ret = pdata->platform_enable_dsipll(); + if (ret < 0) { + dev_warn(&mcde_dev->dev, "%s: " + "enable_dsipll failed ret = %d\n", + __func__, ret); + goto enable_dsipll_err; + } + dev_dbg(&mcde_dev->dev, "%s enable dsipll\n", + __func__); + } + dsi_pll_is_enabled++; + } + + dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, LINK_EN, true); + + if (dsi_rfld(link, DSI_MCTL_LANE_STS, CLKLANE_STATE) == + DSI_LANE_STATE_ULPM || + dsi_rfld(link, DSI_MCTL_LANE_STS, DATLANE1_STATE) + == DSI_LANE_STATE_ULPM || + dsi_rfld(link, DSI_MCTL_LANE_STS, DATLANE2_STATE) + == DSI_LANE_STATE_ULPM) { + /* Switch hs clock to sys_clk */ + dsi_wfld(link, DSI_MCTL_PLL_CTL, PLL_OUT_SEL, 0x1); + dsi_link_handle_ulpm(&chnl->port, false); + /* Switch hs clock to tx_byte_hs_clk */ + dsi_wfld(link, DSI_MCTL_PLL_CTL, PLL_OUT_SEL, 0x0); + } + + dev_dbg(&mcde_dev->dev, "DSI%d LINK_EN\n", link); + + return 0; + +enable_dsipll_err: + clk_disable(clock_dsi_lp); + clk_disable(clock_dsi); + return ret; +} + +static void dsi_link_disable(struct mcde_chnl_state *chnl, bool suspend) +{ + wait_while_dsi_running(chnl->port.link); + /* only enter ULPM when device is suspended */ + if (suspend) + dsi_link_handle_ulpm(&chnl->port, true); + if (dsi_use_clk_framework) { + clk_disable(chnl->clk_dsi_lp); + clk_disable(chnl->clk_dsi_hs); + } else { + if (dsi_pll_is_enabled && (--dsi_pll_is_enabled == 0)) { + struct mcde_platform_data *pdata = + mcde_dev->dev.platform_data; + dev_dbg(&mcde_dev->dev, "%s disable dsipll\n", + __func__); + pdata->platform_disable_dsipll(); + } + clk_disable(clock_dsi); + clk_disable(clock_dsi_lp); + } + + dsi_wfld(chnl->port.link, DSI_MCTL_MAIN_DATA_CTL, LINK_EN, false); +} + +static void disable_mcde_hw(bool force_disable, bool suspend) +{ + int i; + bool mcde_up = false; + + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (!mcde_is_enabled) + return; + + for (i = 0; i < num_channels; i++) { + struct mcde_chnl_state *chnl = &channels[i]; + if (force_disable || (chnl->enabled && + chnl->state != CHNLSTATE_RUNNING)) { + stop_channel(chnl); + set_channel_state_sync(chnl, CHNLSTATE_SUSPEND); + + if (chnl->formatter_updated) { + if (chnl->port.type == MCDE_PORTTYPE_DSI) + dsi_link_disable(chnl, suspend); + else if (chnl->port.type == MCDE_PORTTYPE_DPI) + clk_disable(chnl->clk_dpi); + chnl->formatter_updated = false; + } + if (chnl->esram_is_enabled) { + WARN_ON_ONCE(regulator_disable( + regulator_esram_epod)); + chnl->esram_is_enabled = false; + } + } else if (chnl->enabled && chnl->state == CHNLSTATE_RUNNING) { + mcde_up = true; + } + } + + if (mcde_up) + return; + + free_irq(mcde_irq, &mcde_dev->dev); + + disable_clocks_and_power(mcde_dev); + + mcde_is_enabled = false; +} + +static void dpi_video_mode_apply(struct mcde_chnl_state *chnl) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + chnl->tv_regs.interlaced_en = chnl->vmode.interlaced; + + chnl->tv_regs.sel_mode_tv = chnl->port.phy.dpi.tv_mode; + if (chnl->tv_regs.sel_mode_tv) { + /* TV mode */ + u32 bel; + /* -4 since hsw is excluding SAV/EAV, 2 bytes each */ + chnl->tv_regs.hsw = chnl->vmode.hbp + chnl->vmode.hfp - 4; + /* vbp_field2 = vbp_field1 + 1 */ + chnl->tv_regs.fsl1 = chnl->vmode.vbp / 2; + chnl->tv_regs.fsl2 = chnl->vmode.vbp - chnl->tv_regs.fsl1; + /* +1 since vbp_field2 = vbp_field1 + 1 */ + bel = chnl->vmode.vbp + chnl->vmode.vfp; + /* in TV mode: bel2 = bel1 + 1 */ + chnl->tv_regs.bel1 = bel / 2; + chnl->tv_regs.bel2 = bel - chnl->tv_regs.bel1; + if (chnl->port.phy.dpi.bus_width == 4) + chnl->tv_regs.tv_mode = MCDE_TVCRA_TVMODE_SDTV_656P_BE; + else + chnl->tv_regs.tv_mode = MCDE_TVCRA_TVMODE_SDTV_656P; + chnl->tv_regs.inv_clk = true; + } else { + /* LCD mode */ + u32 polarity; + chnl->tv_regs.hsw = chnl->vmode.hsw; + chnl->tv_regs.dho = chnl->vmode.hbp; + chnl->tv_regs.alw = chnl->vmode.hfp; + chnl->tv_regs.bel1 = chnl->vmode.vsw; + chnl->tv_regs.bel2 = chnl->tv_regs.bel1; + chnl->tv_regs.dvo = chnl->vmode.vbp; + chnl->tv_regs.bsl = chnl->vmode.vfp; + chnl->tv_regs.fsl1 = 0; + chnl->tv_regs.fsl2 = 0; + polarity = chnl->port.phy.dpi.polarity; + chnl->tv_regs.lcdtim1 = MCDE_LCDTIM1A_IHS( + (polarity & DPI_ACT_LOW_HSYNC) != 0); + chnl->tv_regs.lcdtim1 |= MCDE_LCDTIM1A_IVS( + (polarity & DPI_ACT_LOW_VSYNC) != 0); + chnl->tv_regs.lcdtim1 |= MCDE_LCDTIM1A_IOE( + (polarity & DPI_ACT_LOW_DATA_ENABLE) != 0); + chnl->tv_regs.lcdtim1 |= MCDE_LCDTIM1A_IPC( + (polarity & DPI_ACT_ON_FALLING_EDGE) != 0); + } + chnl->tv_regs.dirty = true; +} + +static void update_dpi_registers(enum mcde_chnl chnl_id, struct tv_regs *regs) +{ + u8 idx = chnl_id; + + dev_dbg(&mcde_dev->dev, "%s\n", __func__); + mcde_wreg(MCDE_TVCRA + idx * MCDE_TVCRA_GROUPOFFSET, + MCDE_TVCRA_SEL_MOD(regs->sel_mode_tv) | + MCDE_TVCRA_INTEREN(regs->interlaced_en) | + MCDE_TVCRA_IFIELD(0) | + MCDE_TVCRA_TVMODE(regs->tv_mode) | + MCDE_TVCRA_SDTVMODE(MCDE_TVCRA_SDTVMODE_Y0CBY1CR) | + MCDE_TVCRA_CKINV(regs->inv_clk) | + MCDE_TVCRA_AVRGEN(0)); + mcde_wreg(MCDE_TVBLUA + idx * MCDE_TVBLUA_GROUPOFFSET, + MCDE_TVBLUA_TVBLU(MCDE_CONFIG_TVOUT_BACKGROUND_LUMINANCE) | + MCDE_TVBLUA_TVBCB(MCDE_CONFIG_TVOUT_BACKGROUND_CHROMINANCE_CB)| + MCDE_TVBLUA_TVBCR(MCDE_CONFIG_TVOUT_BACKGROUND_CHROMINANCE_CR)); + + /* Vertical timing registers */ + mcde_wreg(MCDE_TVDVOA + idx * MCDE_TVDVOA_GROUPOFFSET, + MCDE_TVDVOA_DVO1(regs->dvo) | + MCDE_TVDVOA_DVO2(regs->dvo)); + mcde_wreg(MCDE_TVBL1A + idx * MCDE_TVBL1A_GROUPOFFSET, + MCDE_TVBL1A_BEL1(regs->bel1) | + MCDE_TVBL1A_BSL1(regs->bsl)); + mcde_wreg(MCDE_TVBL2A + idx * MCDE_TVBL1A_GROUPOFFSET, + MCDE_TVBL2A_BEL2(regs->bel2) | + MCDE_TVBL2A_BSL2(regs->bsl)); + mcde_wreg(MCDE_TVISLA + idx * MCDE_TVISLA_GROUPOFFSET, + MCDE_TVISLA_FSL1(regs->fsl1) | + MCDE_TVISLA_FSL2(regs->fsl2)); + + /* Horizontal timing registers */ + mcde_wreg(MCDE_TVLBALWA + idx * MCDE_TVLBALWA_GROUPOFFSET, + MCDE_TVLBALWA_LBW(regs->hsw) | + MCDE_TVLBALWA_ALW(regs->alw)); + mcde_wreg(MCDE_TVTIM1A + idx * MCDE_TVTIM1A_GROUPOFFSET, + MCDE_TVTIM1A_DHO(regs->dho)); + if (!regs->sel_mode_tv) + mcde_wreg(MCDE_LCDTIM1A + idx * MCDE_LCDTIM1A_GROUPOFFSET, + regs->lcdtim1); + regs->dirty = false; +} + +static void update_col_registers(enum mcde_chnl chnl_id, struct col_regs *regs) +{ + u8 idx = chnl_id; + + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + mcde_wreg(MCDE_RGBCONV1A + idx * MCDE_RGBCONV1A_GROUPOFFSET, + MCDE_RGBCONV1A_YR_RED(regs->y_red) | + MCDE_RGBCONV1A_YR_GREEN(regs->y_green)); + mcde_wreg(MCDE_RGBCONV2A + idx * MCDE_RGBCONV2A_GROUPOFFSET, + MCDE_RGBCONV2A_YR_BLUE(regs->y_blue) | + MCDE_RGBCONV2A_CR_RED(regs->cr_red)); + mcde_wreg(MCDE_RGBCONV3A + idx * MCDE_RGBCONV3A_GROUPOFFSET, + MCDE_RGBCONV3A_CR_GREEN(regs->cr_green) | + MCDE_RGBCONV3A_CR_BLUE(regs->cr_blue)); + mcde_wreg(MCDE_RGBCONV4A + idx * MCDE_RGBCONV4A_GROUPOFFSET, + MCDE_RGBCONV4A_CB_RED(regs->cb_red) | + MCDE_RGBCONV4A_CB_GREEN(regs->cb_green)); + mcde_wreg(MCDE_RGBCONV5A + idx * MCDE_RGBCONV5A_GROUPOFFSET, + MCDE_RGBCONV5A_CB_BLUE(regs->cb_blue) | + MCDE_RGBCONV5A_OFF_RED(regs->off_cr)); + mcde_wreg(MCDE_RGBCONV6A + idx * MCDE_RGBCONV6A_GROUPOFFSET, + MCDE_RGBCONV6A_OFF_GREEN(regs->off_y) | + MCDE_RGBCONV6A_OFF_BLUE(regs->off_cb)); + regs->dirty = false; +} + +/* MCDE internal helpers */ +static u8 portfmt2dsipacking(enum mcde_port_pix_fmt pix_fmt) +{ + switch (pix_fmt) { + case MCDE_PORTPIXFMT_DSI_16BPP: + return MCDE_DSIVID0CONF0_PACKING_RGB565; + case MCDE_PORTPIXFMT_DSI_18BPP_PACKED: + return MCDE_DSIVID0CONF0_PACKING_RGB666; + case MCDE_PORTPIXFMT_DSI_18BPP: + case MCDE_PORTPIXFMT_DSI_24BPP: + default: + return MCDE_DSIVID0CONF0_PACKING_RGB888; + case MCDE_PORTPIXFMT_DSI_YCBCR422: + return MCDE_DSIVID0CONF0_PACKING_HDTV; + } +} + +static u8 portfmt2bpp(enum mcde_port_pix_fmt pix_fmt) +{ + /* TODO: Check DPI spec *//* REVIEW: Remove or check */ + switch (pix_fmt) { + case MCDE_PORTPIXFMT_DPI_16BPP_C1: + case MCDE_PORTPIXFMT_DPI_16BPP_C2: + case MCDE_PORTPIXFMT_DPI_16BPP_C3: + case MCDE_PORTPIXFMT_DSI_16BPP: + case MCDE_PORTPIXFMT_DSI_YCBCR422: + return 16; + case MCDE_PORTPIXFMT_DPI_18BPP_C1: + case MCDE_PORTPIXFMT_DPI_18BPP_C2: + case MCDE_PORTPIXFMT_DSI_18BPP_PACKED: + return 18; + case MCDE_PORTPIXFMT_DSI_18BPP: + case MCDE_PORTPIXFMT_DPI_24BPP: + case MCDE_PORTPIXFMT_DSI_24BPP: + return 24; + default: + return 1; + } +} + +static u8 bpp2outbpp(u8 bpp) +{ + switch (bpp) { + case 16: + return MCDE_CRA1_OUTBPP_16BPP; + case 18: + return MCDE_CRA1_OUTBPP_18BPP; + case 24: + return MCDE_CRA1_OUTBPP_24BPP; + default: + return 0; + } +} + +static u8 portfmt2cdwin(enum mcde_port_pix_fmt pix_fmt) +{ + switch (pix_fmt) { + case MCDE_PORTPIXFMT_DPI_16BPP_C1: + return MCDE_CRA1_CDWIN_16BPP_C1; + case MCDE_PORTPIXFMT_DPI_16BPP_C2: + return MCDE_CRA1_CDWIN_16BPP_C2; + case MCDE_PORTPIXFMT_DPI_16BPP_C3: + return MCDE_CRA1_CDWIN_16BPP_C3; + case MCDE_PORTPIXFMT_DPI_18BPP_C1: + return MCDE_CRA1_CDWIN_18BPP_C1; + case MCDE_PORTPIXFMT_DPI_18BPP_C2: + return MCDE_CRA1_CDWIN_18BPP_C2; + case MCDE_PORTPIXFMT_DPI_24BPP: + return MCDE_CRA1_CDWIN_24BPP; + default: + /* only DPI formats are relevant */ + return 0; + } +} + +static u32 get_output_fifo_size(enum mcde_fifo fifo) +{ + u32 ret = 1; /* Avoid div by zero */ + + switch (fifo) { + case MCDE_FIFO_A: + case MCDE_FIFO_B: + ret = output_fifo_ab_size; + break; + case MCDE_FIFO_C0: + case MCDE_FIFO_C1: + ret = output_fifo_c0c1_size; + break; + default: + dev_warn(&mcde_dev->dev, "Unsupported fifo"); + break; + } + return ret; +} + +static inline u8 get_dsi_formatter_id(const struct mcde_port *port) +{ + if (dsi_ifc_is_supported) + return 2 * port->link + port->ifc; + else + return port->link; +} + +static struct mcde_chnl_state *find_channel_by_dsilink(int link) +{ + struct mcde_chnl_state *chnl = &channels[0]; + for (; chnl < &channels[num_channels]; chnl++) + if (chnl->enabled && chnl->port.link == link && + chnl->port.type == MCDE_PORTTYPE_DSI) + return chnl; + return NULL; +} + +static inline void mcde_handle_vcmp(struct mcde_chnl_state *chnl) +{ + if (!chnl->vcmp_per_field || + (chnl->vcmp_per_field && chnl->even_vcmp)) { + atomic_inc(&chnl->vcmp_cnt); + if (chnl->state == CHNLSTATE_STOPPING) + set_channel_state_atomic(chnl, CHNLSTATE_STOPPED); + wake_up_all(&chnl->vcmp_waitq); + } + chnl->even_vcmp = !chnl->even_vcmp; +} + +static void handle_dsi_irq(struct mcde_chnl_state *chnl, int i) +{ + u32 irq_status = dsi_rfld(i, DSI_DIRECT_CMD_STS_FLAG, TE_RECEIVED_FLAG); + if (irq_status) { + dsi_wreg(i, DSI_DIRECT_CMD_STS_CLR, + DSI_DIRECT_CMD_STS_CLR_TE_RECEIVED_CLR(true)); + dev_vdbg(&mcde_dev->dev, "BTA TE DSI%d\n", i); + do_softwaretrig(chnl); + } + + irq_status = dsi_rfld(i, DSI_CMD_MODE_STS_FLAG, ERR_NO_TE_FLAG); + if (irq_status) { + dsi_wreg(i, DSI_CMD_MODE_STS_CLR, + DSI_CMD_MODE_STS_CLR_ERR_NO_TE_CLR(true)); + dev_warn(&mcde_dev->dev, "NO_TE DSI%d\n", i); + set_channel_state_atomic(chnl, CHNLSTATE_STOPPED); + } + + irq_status = dsi_rfld(i, DSI_DIRECT_CMD_STS, TRIGGER_RECEIVED); + if (irq_status) { + /* DSI TE polling answer received */ + dsi_wreg(i, DSI_DIRECT_CMD_STS_CLR, + DSI_DIRECT_CMD_STS_CLR_TRIGGER_RECEIVED_CLR(true)); + + /* Reset TE watchdog timer */ + if (chnl->port.sync_src == MCDE_SYNCSRC_TE_POLLING) + dsi_te_poll_set_timer(chnl, DSI_TE_NO_ANSWER_TIMEOUT); + } +} + +static irqreturn_t mcde_irq_handler(int irq, void *dev) +{ + int i; + u32 irq_status; + + irq_status = mcde_rreg(MCDE_MISCHNL); + if (irq_status) { + dev_err(&mcde_dev->dev, "chnl error=%.8x\n", irq_status); + mcde_wreg(MCDE_RISCHNL, irq_status); + } + irq_status = mcde_rreg(MCDE_MISERR); + if (irq_status) { + dev_err(&mcde_dev->dev, "error=%.8x\n", irq_status); + mcde_wreg(MCDE_RISERR, irq_status); + } + + /* Handle channel irqs */ + irq_status = mcde_rreg(MCDE_RISPP); + if (irq_status & MCDE_RISPP_VCMPARIS_MASK) + mcde_handle_vcmp(&channels[MCDE_CHNL_A]); + if (irq_status & MCDE_RISPP_VCMPBRIS_MASK) + mcde_handle_vcmp(&channels[MCDE_CHNL_B]); + if (irq_status & MCDE_RISPP_VCMPC0RIS_MASK) + mcde_handle_vcmp(&channels[MCDE_CHNL_C0]); + if (irq_status & MCDE_RISPP_VCMPC1RIS_MASK) + mcde_handle_vcmp(&channels[MCDE_CHNL_C1]); + mcde_wreg(MCDE_RISPP, irq_status); + + for (i = 0; i < num_dsilinks; i++) { + struct mcde_chnl_state *chnl_from_dsi; + + chnl_from_dsi = find_channel_by_dsilink(i); + + if (chnl_from_dsi == NULL) + continue; + + handle_dsi_irq(chnl_from_dsi, i); + } + + return IRQ_HANDLED; +} + +/* Transitions allowed: WAIT_TE -> UPDATE -> STOPPING */ +static int set_channel_state_atomic(struct mcde_chnl_state *chnl, + enum chnl_state state) +{ + enum chnl_state chnl_state = chnl->state; + + dev_dbg(&mcde_dev->dev, "Channel state change" + " (chnl=%d, old=%d, new=%d)\n", chnl->id, chnl_state, state); + + if ((chnl_state == CHNLSTATE_SETUP && state == CHNLSTATE_WAIT_TE) || + (chnl_state == CHNLSTATE_SETUP && state == CHNLSTATE_RUNNING) || + (chnl_state == CHNLSTATE_WAIT_TE && state == CHNLSTATE_RUNNING) || + (chnl_state == CHNLSTATE_RUNNING && state == CHNLSTATE_STOPPING)) { + /* Set wait TE, running, or stopping state */ + chnl->state = state; + return 0; + } else if ((chnl_state == CHNLSTATE_STOPPING && + state == CHNLSTATE_STOPPED) || + (chnl_state == CHNLSTATE_WAIT_TE && + state == CHNLSTATE_STOPPED)) { + /* Set stopped state */ + chnl->state = state; + wake_up_all(&chnl->state_waitq); + return 0; + } else if (state == CHNLSTATE_IDLE) { + /* Set idle state */ + WARN_ON_ONCE(chnl_state != CHNLSTATE_DSI_READ && + chnl_state != CHNLSTATE_DSI_WRITE && + chnl_state != CHNLSTATE_SUSPEND); + chnl->state = state; + wake_up_all(&chnl->state_waitq); + return 0; + } else { + /* Invalid atomic state transition */ + dev_warn(&mcde_dev->dev, "Channel state change error (chnl=%d," + " old=%d, new=%d)\n", chnl->id, chnl_state, state); + WARN_ON_ONCE(true); + return -EINVAL; + } +} + +/* LOCKING: mcde_hw_lock */ +static int set_channel_state_sync(struct mcde_chnl_state *chnl, + enum chnl_state state) +{ + int ret = 0; + enum chnl_state chnl_state = chnl->state; + + dev_dbg(&mcde_dev->dev, "Channel state change" + " (chnl=%d, old=%d, new=%d)\n", chnl->id, chnl->state, state); + + /* No change */ + if (chnl_state == state) + return 0; + + /* Wait for IDLE before changing state */ + if (chnl_state != CHNLSTATE_IDLE) { + ret = wait_event_timeout(chnl->state_waitq, + /* STOPPED -> IDLE is manual, so wait for both */ + chnl->state == CHNLSTATE_STOPPED || + chnl->state == CHNLSTATE_IDLE, + msecs_to_jiffies(CHNL_TIMEOUT)); + if (WARN_ON_ONCE(!ret)) + dev_warn(&mcde_dev->dev, "Wait for channel timeout " + "(chnl=%d, curr=%d, new=%d)\n", + chnl->id, chnl->state, state); + chnl_state = chnl->state; + } + + /* Do manual transition from STOPPED to IDLE */ + if (chnl_state == CHNLSTATE_STOPPED) + wait_for_flow_disabled(chnl); + + /* State is IDLE, do transition to new state */ + chnl->state = state; + + return ret; +} + +static int wait_for_vcmp(struct mcde_chnl_state *chnl) +{ + u64 vcmp = atomic_read(&chnl->vcmp_cnt) + 1; + int ret = wait_event_timeout(chnl->vcmp_waitq, + atomic_read(&chnl->vcmp_cnt) >= vcmp, + msecs_to_jiffies(CHNL_TIMEOUT)); + return ret; +} + +static void get_vid_operating_mode(const struct mcde_port *port, + bool *burst_mode, bool *sync_is_pulse, bool *tvg_enable) +{ + switch (port->phy.dsi.vid_mode) { + case NON_BURST_MODE_WITH_SYNC_EVENT: + *burst_mode = false; + *sync_is_pulse = false; + *tvg_enable = false; + break; + case NON_BURST_MODE_WITH_SYNC_EVENT_TVG_ENABLED: + *burst_mode = false; + *sync_is_pulse = false; + *tvg_enable = true; + break; + case BURST_MODE_WITH_SYNC_EVENT: + *burst_mode = true; + *sync_is_pulse = false; + *tvg_enable = false; + break; + case BURST_MODE_WITH_SYNC_PULSE: + *burst_mode = true; + *sync_is_pulse = true; + *tvg_enable = false; + break; + default: + dev_err(&mcde_dev->dev, "Unsupported video mode"); + break; + } +} + +static void update_vid_static_registers(const struct mcde_port *port) +{ + u8 link = port->link; + bool burst_mode, sync_is_pulse, tvg_enable; + + get_vid_operating_mode(port, &burst_mode, &sync_is_pulse, &tvg_enable); + + /* burst mode or non-burst mode */ + dsi_wfld(link, DSI_VID_MAIN_CTL, BURST_MODE, burst_mode); + + /* sync is pulse or event */ + dsi_wfld(link, DSI_VID_MAIN_CTL, SYNC_PULSE_ACTIVE, sync_is_pulse); + dsi_wfld(link, DSI_VID_MAIN_CTL, SYNC_PULSE_HORIZONTAL, sync_is_pulse); + + /* disable video stream when using TVG */ + if (tvg_enable) { + dsi_wfld(link, DSI_MCTL_MAIN_EN, IF1_EN, false); + dsi_wfld(link, DSI_MCTL_MAIN_EN, IF2_EN, false); + } + + /* + * behavior during blanking time + * 00: NULL packet 1x:LP 01:blanking-packet + */ + dsi_wfld(link, DSI_VID_MAIN_CTL, REG_BLKLINE_MODE, 1); + + /* + * behavior during eol + * 00: NULL packet 1x:LP 01:blanking-packet + */ + dsi_wfld(link, DSI_VID_MAIN_CTL, REG_BLKEOL_MODE, 2); + + /* time to perform LP->HS on D-PHY */ + dsi_wfld(link, DSI_VID_DPHY_TIME, REG_WAKEUP_TIME, + port->phy.dsi.vid_wakeup_time); + + /* + * video stream starts on VSYNC packet + * and stops at the end of a frame + */ + dsi_wfld(link, DSI_VID_MAIN_CTL, VID_ID, port->phy.dsi.virt_id); + dsi_wfld(link, DSI_VID_MAIN_CTL, START_MODE, 0); + dsi_wfld(link, DSI_VID_MAIN_CTL, STOP_MODE, 0); + + /* 1: if1 in video mode, 0: if1 in command mode */ + dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, IF1_MODE, 1); + + /* 1: enables the link, 0: disables the link */ + dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, VID_EN, 1); +} + +static int update_channel_static_registers(struct mcde_chnl_state *chnl) +{ + const struct mcde_port *port = &chnl->port; + + switch (chnl->fifo) { + case MCDE_FIFO_A: + mcde_wreg(MCDE_CHNL0MUXING + chnl->id * + MCDE_CHNL0MUXING_GROUPOFFSET, + MCDE_CHNL0MUXING_FIFO_ID_ENUM(FIFO_A)); + if (port->type == MCDE_PORTTYPE_DPI) { + mcde_wfld(MCDE_CTRLA, FORMTYPE, + MCDE_CTRLA_FORMTYPE_DPITV); + mcde_wfld(MCDE_CTRLA, FORMID, port->link); + } else if (port->type == MCDE_PORTTYPE_DSI) { + mcde_wfld(MCDE_CTRLA, FORMTYPE, + MCDE_CTRLA_FORMTYPE_DSI); + mcde_wfld(MCDE_CTRLA, FORMID, + get_dsi_formatter_id(port)); + } + break; + case MCDE_FIFO_B: + mcde_wreg(MCDE_CHNL0MUXING + chnl->id * + MCDE_CHNL0MUXING_GROUPOFFSET, + MCDE_CHNL0MUXING_FIFO_ID_ENUM(FIFO_B)); + if (port->type == MCDE_PORTTYPE_DPI) { + mcde_wfld(MCDE_CTRLB, FORMTYPE, + MCDE_CTRLB_FORMTYPE_DPITV); + mcde_wfld(MCDE_CTRLB, FORMID, port->link); + } else if (port->type == MCDE_PORTTYPE_DSI) { + mcde_wfld(MCDE_CTRLB, FORMTYPE, + MCDE_CTRLB_FORMTYPE_DSI); + mcde_wfld(MCDE_CTRLB, FORMID, + get_dsi_formatter_id(port)); + } + + break; + case MCDE_FIFO_C0: + mcde_wreg(MCDE_CHNL0MUXING + chnl->id * + MCDE_CHNL0MUXING_GROUPOFFSET, + MCDE_CHNL0MUXING_FIFO_ID_ENUM(FIFO_C0)); + if (port->type == MCDE_PORTTYPE_DPI) + return -EINVAL; + mcde_wfld(MCDE_CTRLC0, FORMTYPE, + MCDE_CTRLC0_FORMTYPE_DSI); + mcde_wfld(MCDE_CTRLC0, FORMID, get_dsi_formatter_id(port)); + break; + case MCDE_FIFO_C1: + mcde_wreg(MCDE_CHNL0MUXING + chnl->id * + MCDE_CHNL0MUXING_GROUPOFFSET, + MCDE_CHNL0MUXING_FIFO_ID_ENUM(FIFO_C1)); + if (port->type == MCDE_PORTTYPE_DPI) + return -EINVAL; + mcde_wfld(MCDE_CTRLC1, FORMTYPE, + MCDE_CTRLC1_FORMTYPE_DSI); + mcde_wfld(MCDE_CTRLC1, FORMID, get_dsi_formatter_id(port)); + break; + default: + return -EINVAL; + } + + /* Formatter */ + if (port->type == MCDE_PORTTYPE_DSI) { + int i = 0; + u8 idx; + u8 lnk = port->link; + + idx = get_dsi_formatter_id(port); + + if (dsi_link_enable(chnl)) + goto failed_to_enable_link; + + if (port->sync_src == MCDE_SYNCSRC_TE_POLLING) { + /* Enable DSI TE polling */ + dsi_te_poll_req(chnl); + + /* Set timer to detect non TE answer */ + dsi_te_poll_set_timer(chnl, + DSI_TE_NO_ANSWER_TIMEOUT_INIT); + } else { + dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, BTA_EN, true); + dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, READ_EN, true); + dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, REG_TE_EN, true); + } + + dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, HOST_EOT_GEN, + port->phy.dsi.host_eot_gen); + + dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, DLX_REMAP_EN, + port->phy.dsi.data_lanes_swap); + + dsi_wreg(lnk, DSI_MCTL_DPHY_STATIC, + DSI_MCTL_DPHY_STATIC_UI_X4(port->phy.dsi.ui)); + dsi_wreg(lnk, DSI_DPHY_LANES_TRIM, + DSI_DPHY_LANES_TRIM_DPHY_SPECS_90_81B_ENUM(0_90)); + dsi_wreg(lnk, DSI_MCTL_DPHY_TIMEOUT, + DSI_MCTL_DPHY_TIMEOUT_CLK_DIV(0xf) | + DSI_MCTL_DPHY_TIMEOUT_HSTX_TO_VAL(0x3fff) | + DSI_MCTL_DPHY_TIMEOUT_LPRX_TO_VAL(0x3fff)); + dsi_wreg(lnk, DSI_MCTL_MAIN_PHY_CTL, + DSI_MCTL_MAIN_PHY_CTL_WAIT_BURST_TIME(0xf) | + DSI_MCTL_MAIN_PHY_CTL_CLK_ULPM_EN(true) | + DSI_MCTL_MAIN_PHY_CTL_DAT1_ULPM_EN(true) | + DSI_MCTL_MAIN_PHY_CTL_DAT2_ULPM_EN(true) | + DSI_MCTL_MAIN_PHY_CTL_LANE2_EN( + port->phy.dsi.num_data_lanes >= 2) | + DSI_MCTL_MAIN_PHY_CTL_CLK_CONTINUOUS( + port->phy.dsi.clk_cont)); + /* TODO: make enum */ + dsi_wfld(lnk, DSI_CMD_MODE_CTL, ARB_MODE, false); + /* TODO: make enum */ + dsi_wfld(lnk, DSI_CMD_MODE_CTL, ARB_PRI, port->ifc == 1); + dsi_wreg(lnk, DSI_MCTL_MAIN_EN, + DSI_MCTL_MAIN_EN_PLL_START(true) | + DSI_MCTL_MAIN_EN_CKLANE_EN(true) | + DSI_MCTL_MAIN_EN_DAT1_EN(true) | + DSI_MCTL_MAIN_EN_DAT2_EN(port->phy.dsi.num_data_lanes + == 2) | + DSI_MCTL_MAIN_EN_IF1_EN(port->ifc == 0) | + DSI_MCTL_MAIN_EN_IF2_EN(port->ifc == 1)); + while (dsi_rfld(lnk, DSI_MCTL_MAIN_STS, CLKLANE_READY) == 0 || + dsi_rfld(lnk, DSI_MCTL_MAIN_STS, DAT1_READY) == 0 || + (dsi_rfld(lnk, DSI_MCTL_MAIN_STS, DAT2_READY) == 0 && + port->phy.dsi.num_data_lanes > 1)) { + mdelay(1); + if (i++ == 10) { + dev_warn(&mcde_dev->dev, + "DSI lane not ready (link=%d)!\n", lnk); + goto dsi_link_error; + } + } + + mcde_wreg(MCDE_DSIVID0CONF0 + + idx * MCDE_DSIVID0CONF0_GROUPOFFSET, + MCDE_DSIVID0CONF0_BLANKING(0) | + MCDE_DSIVID0CONF0_VID_MODE( + port->mode == MCDE_PORTMODE_VID) | + MCDE_DSIVID0CONF0_CMD8(true) | + MCDE_DSIVID0CONF0_BIT_SWAP(false) | + MCDE_DSIVID0CONF0_BYTE_SWAP(false) | + MCDE_DSIVID0CONF0_DCSVID_NOTGEN(true)); + + if (port->mode == MCDE_PORTMODE_VID) { + update_vid_static_registers(port); + } else { + if (port->ifc == 0) + dsi_wfld(port->link, DSI_CMD_MODE_CTL, IF1_ID, + port->phy.dsi.virt_id); + else if (port->ifc == 1) + dsi_wfld(port->link, DSI_CMD_MODE_CTL, IF2_ID, + port->phy.dsi.virt_id); + } + } + + if (port->type == MCDE_PORTTYPE_DPI) { + if (port->phy.dpi.lcd_freq != clk_round_rate(chnl->clk_dpi, + port->phy.dpi.lcd_freq)) + dev_warn(&mcde_dev->dev, "Could not set lcd freq" + " to %d\n", port->phy.dpi.lcd_freq); + WARN_ON_ONCE(clk_set_rate(chnl->clk_dpi, + port->phy.dpi.lcd_freq)); + WARN_ON_ONCE(clk_enable(chnl->clk_dpi)); + } + + mcde_wfld(MCDE_CR, MCDEEN, true); + chnl->formatter_updated = true; + + dev_vdbg(&mcde_dev->dev, "Static registers setup, chnl=%d\n", chnl->id); + + return 0; +dsi_link_error: + dsi_link_disable(chnl, true); +failed_to_enable_link: + return -EINVAL; +} + +void mcde_chnl_col_convert_apply(struct mcde_chnl_state *chnl, + struct mcde_col_transform *transform) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (chnl->transform != transform) { + + chnl->col_regs.y_red = transform->matrix[0][0]; + chnl->col_regs.y_green = transform->matrix[0][1]; + chnl->col_regs.y_blue = transform->matrix[0][2]; + chnl->col_regs.cb_red = transform->matrix[1][0]; + chnl->col_regs.cb_green = transform->matrix[1][1]; + chnl->col_regs.cb_blue = transform->matrix[1][2]; + chnl->col_regs.cr_red = transform->matrix[2][0]; + chnl->col_regs.cr_green = transform->matrix[2][1]; + chnl->col_regs.cr_blue = transform->matrix[2][2]; + chnl->col_regs.off_y = transform->offset[0]; + chnl->col_regs.off_cb = transform->offset[1]; + chnl->col_regs.off_cr = transform->offset[2]; + chnl->col_regs.dirty = true; + + chnl->transform = transform; + } + + dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__); +} + +static void chnl_ovly_pixel_format_apply(struct mcde_chnl_state *chnl, + struct mcde_ovly_state *ovly) +{ + struct mcde_port *port = &chnl->port; + struct ovly_regs *regs = &ovly->regs; + + /* Note: YUV -> YUV: blending YUV overlays will not make sense. */ + static struct mcde_col_transform crycb_2_ycbcr = { + /* Note that in MCDE YUV 422 pixels come as VYU pixels */ + .matrix = { + {0x0000, 0x0100, 0x0000}, + {0x0000, 0x0000, 0x0100}, + {0x0100, 0x0000, 0x0000}, + }, + .offset = {0, 0, 0}, + }; + + if (port->type == MCDE_PORTTYPE_DSI) { + if (port->pixel_format != MCDE_PORTPIXFMT_DSI_YCBCR422) { + if (ovly->pix_fmt != MCDE_OVLYPIXFMT_YCbCr422) { + /* standard case: DSI: RGB -> RGB */ + regs->col_conv = MCDE_OVL0CR_COLCCTRL_DISABLED; + } else { + /* DSI: YUV -> RGB */ + /* TODO change matrix */ + regs->col_conv = + MCDE_OVL0CR_COLCCTRL_ENABLED_SAT; + mcde_chnl_col_convert_apply(chnl, + &chnl->ycbcr_2_rgb); + } + } else { + if (ovly->pix_fmt != MCDE_OVLYPIXFMT_YCbCr422) + /* DSI: RGB -> YUV */ + mcde_chnl_col_convert_apply(chnl, + &chnl->rgb_2_ycbcr); + else + /* DSI: YUV -> YUV */ + mcde_chnl_col_convert_apply(chnl, + &crycb_2_ycbcr); + regs->col_conv = MCDE_OVL0CR_COLCCTRL_ENABLED_NO_SAT; + } + } else if (port->type == MCDE_PORTTYPE_DPI && port->phy.dpi.tv_mode) { + regs->col_conv = MCDE_OVL0CR_COLCCTRL_ENABLED_NO_SAT; + if (ovly->pix_fmt != MCDE_OVLYPIXFMT_YCbCr422) + mcde_chnl_col_convert_apply(chnl, &chnl->rgb_2_ycbcr); + else + mcde_chnl_col_convert_apply(chnl, &crycb_2_ycbcr); + } else if (port->type == MCDE_PORTTYPE_DPI) { + /* Note: YUV is not support port pixel format for DPI */ + if (ovly->pix_fmt != MCDE_OVLYPIXFMT_YCbCr422) { + /* standard case: DPI: RGB -> RGB */ + regs->col_conv = MCDE_OVL0CR_COLCCTRL_DISABLED; + } else { + /* DPI: YUV -> RGB */ + regs->col_conv = + MCDE_OVL0CR_COLCCTRL_ENABLED_SAT; + mcde_chnl_col_convert_apply(chnl, + &chnl->ycbcr_2_rgb); + } + } +} + +/* REVIEW: Make update_* an mcde_rectangle? */ +static void update_overlay_registers(u8 idx, struct ovly_regs *regs, + struct mcde_port *port, enum mcde_fifo fifo, + u16 update_x, u16 update_y, u16 update_w, + u16 update_h, s16 stride, bool interlaced, + enum mcde_display_rotation rotation) +{ + /* TODO: fix clipping for small overlay */ + u32 lmrgn = (regs->cropx + update_x) * regs->bits_per_pixel; + u32 tmrgn = (regs->cropy + update_y) * stride; + u32 ppl = regs->ppl - update_x; + u32 lpf = regs->lpf - update_y; + s32 ljinc = stride; + u32 pixelfetchwtrmrklevel; + u8 nr_of_bufs = 1; + u32 sel_mod = MCDE_EXTSRC0CR_SEL_MOD_SOFTWARE_SEL; + + if (rotation == MCDE_DISPLAY_ROT_180_CCW) { + ljinc = -ljinc; + tmrgn += stride * (regs->lpf - 1) / 8; + } + + /* + * Preferably most of this is done in some apply function instead of for + * every update. However lpf has a dependency on update_y. + */ + if (interlaced && port->type == MCDE_PORTTYPE_DSI) { + nr_of_bufs = 2; + lpf = lpf / 2; + ljinc *= 2; + } + + if ((fifo == MCDE_FIFO_A || fifo == MCDE_FIFO_B) && + regs->ppl >= SCREEN_PPL_HIGH) + pixelfetchwtrmrklevel = input_fifo_size * 2; + else + pixelfetchwtrmrklevel = input_fifo_size / 2; + + if (port->update_auto_trig && port->type == MCDE_PORTTYPE_DSI) { + switch (port->sync_src) { + case MCDE_SYNCSRC_OFF: + sel_mod = MCDE_EXTSRC0CR_SEL_MOD_SOFTWARE_SEL; + break; + case MCDE_SYNCSRC_TE0: + case MCDE_SYNCSRC_TE1: + case MCDE_SYNCSRC_TE_POLLING: + default: + sel_mod = MCDE_EXTSRC0CR_SEL_MOD_AUTO_TOGGLE; + break; + } + } else if (port->type == MCDE_PORTTYPE_DPI) + sel_mod = MCDE_EXTSRC0CR_SEL_MOD_SOFTWARE_SEL; + + mcde_wreg(MCDE_EXTSRC0CONF + idx * MCDE_EXTSRC0CONF_GROUPOFFSET, + MCDE_EXTSRC0CONF_BUF_ID(0) | + MCDE_EXTSRC0CONF_BUF_NB(nr_of_bufs) | + MCDE_EXTSRC0CONF_PRI_OVLID(idx) | + MCDE_EXTSRC0CONF_BPP(regs->bpp) | + MCDE_EXTSRC0CONF_BGR(regs->bgr) | + MCDE_EXTSRC0CONF_BEBO(regs->bebo) | + MCDE_EXTSRC0CONF_BEPO(false)); + mcde_wreg(MCDE_EXTSRC0CR + idx * MCDE_EXTSRC0CR_GROUPOFFSET, + MCDE_EXTSRC0CR_SEL_MOD(sel_mod) | + MCDE_EXTSRC0CR_MULTIOVL_CTRL_ENUM(PRIMARY) | + MCDE_EXTSRC0CR_FS_DIV_DISABLE(false) | + MCDE_EXTSRC0CR_FORCE_FS_DIV(false)); + mcde_wreg(MCDE_OVL0CR + idx * MCDE_OVL0CR_GROUPOFFSET, + MCDE_OVL0CR_OVLEN(regs->enabled) | + MCDE_OVL0CR_COLCCTRL(regs->col_conv) | + MCDE_OVL0CR_CKEYGEN(false) | + MCDE_OVL0CR_ALPHAPMEN(false) | + MCDE_OVL0CR_OVLF(false) | + MCDE_OVL0CR_OVLR(false) | + MCDE_OVL0CR_OVLB(false) | + MCDE_OVL0CR_FETCH_ROPC(0) | + MCDE_OVL0CR_STBPRIO(0) | + MCDE_OVL0CR_BURSTSIZE_ENUM(HW_8W) | + /* TODO: enum, get from ovly */ + MCDE_OVL0CR_MAXOUTSTANDING_ENUM(8_REQ) | + /* TODO: _HW_8W, calculate? */ + MCDE_OVL0CR_ROTBURSTSIZE_ENUM(HW_8W)); + mcde_wreg(MCDE_OVL0CONF + idx * MCDE_OVL0CONF_GROUPOFFSET, + MCDE_OVL0CONF_PPL(ppl) | + MCDE_OVL0CONF_EXTSRC_ID(idx) | + MCDE_OVL0CONF_LPF(lpf)); + mcde_wreg(MCDE_OVL0CONF2 + idx * MCDE_OVL0CONF2_GROUPOFFSET, + MCDE_OVL0CONF2_BP(regs->alpha_source) | + MCDE_OVL0CONF2_ALPHAVALUE(regs->alpha_value) | + MCDE_OVL0CONF2_OPQ(regs->opq) | + MCDE_OVL0CONF2_PIXOFF(lmrgn & 63) | + MCDE_OVL0CONF2_PIXELFETCHERWATERMARKLEVEL( + pixelfetchwtrmrklevel)); + mcde_wreg(MCDE_OVL0LJINC + idx * MCDE_OVL0LJINC_GROUPOFFSET, + ljinc); + mcde_wreg(MCDE_OVL0CROP + idx * MCDE_OVL0CROP_GROUPOFFSET, + MCDE_OVL0CROP_TMRGN(tmrgn) | + MCDE_OVL0CROP_LMRGN(lmrgn >> 6)); + regs->dirty = false; + + dev_vdbg(&mcde_dev->dev, "Overlay registers setup, idx=%d\n", idx); +} + +static void update_overlay_registers_on_the_fly(u8 idx, struct ovly_regs *regs) +{ + mcde_wreg(MCDE_OVL0COMP + idx * MCDE_OVL0COMP_GROUPOFFSET, + MCDE_OVL0COMP_XPOS(regs->xpos) | + MCDE_OVL0COMP_CH_ID(regs->ch_id) | + MCDE_OVL0COMP_YPOS(regs->ypos) | + MCDE_OVL0COMP_Z(regs->z)); + + mcde_wreg(MCDE_EXTSRC0A0 + idx * MCDE_EXTSRC0A0_GROUPOFFSET, + regs->baseaddress0); + mcde_wreg(MCDE_EXTSRC0A1 + idx * MCDE_EXTSRC0A1_GROUPOFFSET, + regs->baseaddress1); + regs->dirty_buf = false; +} + +static void do_softwaretrig(struct mcde_chnl_state *chnl) +{ + unsigned long flags; + + local_irq_save(flags); + + enable_flow(chnl); + mcde_wreg(MCDE_CHNL0SYNCHSW + + chnl->id * MCDE_CHNL0SYNCHSW_GROUPOFFSET, + MCDE_CHNL0SYNCHSW_SW_TRIG(true)); + disable_flow(chnl); + + local_irq_restore(flags); + + dev_vdbg(&mcde_dev->dev, "Software TRIG on channel %d\n", chnl->id); +} + +static void disable_flow(struct mcde_chnl_state *chnl) +{ + unsigned long flags; + + if (WARN_ON_ONCE(chnl->state != CHNLSTATE_RUNNING)) + return; + + local_irq_save(flags); + + switch (chnl->id) { + case MCDE_CHNL_A: + mcde_wfld(MCDE_CRA0, FLOEN, false); + break; + case MCDE_CHNL_B: + mcde_wfld(MCDE_CRB0, FLOEN, false); + break; + case MCDE_CHNL_C0: + mcde_wfld(MCDE_CRC, C1EN, false); + break; + case MCDE_CHNL_C1: + mcde_wfld(MCDE_CRC, C2EN, false); + break; + } + + set_channel_state_atomic(chnl, CHNLSTATE_STOPPING); + + local_irq_restore(flags); +} + +static void stop_channel(struct mcde_chnl_state *chnl) +{ + const struct mcde_port *port = &chnl->port; + bool dpi_lcd_mode; + + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (chnl->state != CHNLSTATE_RUNNING) + return; + + if (port->type == MCDE_PORTTYPE_DSI) { + dsi_wfld(port->link, DSI_MCTL_MAIN_PHY_CTL, CLK_CONTINUOUS, + false); + if (port->sync_src == MCDE_SYNCSRC_TE_POLLING) + del_timer(&chnl->dsi_te_timer); + } + + disable_flow(chnl); + /* + * Needs to manually trigger VCOMP after the channel is + * disabled. For all channels using video mode + * except for dpi lcd. + */ + dpi_lcd_mode = (port->type == MCDE_PORTTYPE_DPI && + !chnl->port.phy.dpi.tv_mode); + + if (chnl->port.update_auto_trig && !dpi_lcd_mode) + mcde_wreg(MCDE_SISPP, 1 << chnl->id); +} + +static void wait_for_flow_disabled(struct mcde_chnl_state *chnl) +{ + int i = 0; + + switch (chnl->id) { + case MCDE_CHNL_A: + for (i = 0; i < MCDE_FLOWEN_MAX_TRIAL; i++) { + if (!mcde_rfld(MCDE_CRA0, FLOEN)) { + dev_vdbg(&mcde_dev->dev, + "Flow (A) disable after >= %d ms\n", i); + break; + } + msleep(1); + } + break; + case MCDE_CHNL_B: + for (i = 0; i < MCDE_FLOWEN_MAX_TRIAL; i++) { + if (!mcde_rfld(MCDE_CRB0, FLOEN)) { + dev_vdbg(&mcde_dev->dev, + "Flow (B) disable after >= %d ms\n", i); + break; + } + msleep(1); + } + break; + case MCDE_CHNL_C0: + for (i = 0; i < MCDE_FLOWEN_MAX_TRIAL; i++) { + if (!mcde_rfld(MCDE_CRC, C1EN)) { + dev_vdbg(&mcde_dev->dev, + "Flow (C1) disable after >= %d ms\n", i); + break; + } + msleep(1); + } + break; + case MCDE_CHNL_C1: + for (i = 0; i < MCDE_FLOWEN_MAX_TRIAL; i++) { + if (!mcde_rfld(MCDE_CRC, C2EN)) { + dev_vdbg(&mcde_dev->dev, + "Flow (C2) disable after >= %d ms\n", i); + break; + } + msleep(1); + } + break; + } + if (i == MCDE_FLOWEN_MAX_TRIAL) + dev_err(&mcde_dev->dev, "%s: channel %d timeout\n", + __func__, chnl->id); +} + +static void enable_flow(struct mcde_chnl_state *chnl) +{ + const struct mcde_port *port = &chnl->port; + + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (port->type == MCDE_PORTTYPE_DSI) + dsi_wfld(port->link, DSI_MCTL_MAIN_PHY_CTL, CLK_CONTINUOUS, + port->phy.dsi.clk_cont); + + /* + * When ROTEN is set, the FLOEN bit will also be set but + * the flow has to be started anyway. + */ + switch (chnl->id) { + case MCDE_CHNL_A: + WARN_ON_ONCE(mcde_rfld(MCDE_CRA0, FLOEN)); + mcde_wfld(MCDE_CRA0, ROTEN, chnl->regs.roten); + mcde_wfld(MCDE_CRA0, FLOEN, true); + break; + case MCDE_CHNL_B: + WARN_ON_ONCE(mcde_rfld(MCDE_CRB0, FLOEN)); + mcde_wfld(MCDE_CRB0, ROTEN, chnl->regs.roten); + mcde_wfld(MCDE_CRB0, FLOEN, true); + break; + case MCDE_CHNL_C0: + WARN_ON_ONCE(mcde_rfld(MCDE_CRC, C1EN)); + mcde_wfld(MCDE_CRC, C1EN, true); + break; + case MCDE_CHNL_C1: + WARN_ON_ONCE(mcde_rfld(MCDE_CRC, C2EN)); + mcde_wfld(MCDE_CRC, C2EN, true); + break; + } + + set_channel_state_atomic(chnl, CHNLSTATE_RUNNING); +} + +static void work_sleep_function(struct work_struct *ptr) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + if (mcde_trylock(__func__, __LINE__)) { + if (mcde_dynamic_power_management) + disable_mcde_hw(false, false); + mcde_unlock(__func__, __LINE__); + } +} + +/* TODO get from register */ +#define MCDE_CLK_FREQ_MHZ 160 +static u32 get_pkt_div(u32 disp_ppl, + struct mcde_port *port, + enum mcde_fifo fifo) +{ + /* + * The lines can be split in several packets only on DSI CMD mode. + * In DSI VIDEO mode, 1 line = 1 packet. + * DPI is like DSI VIDEO (watermark = 1 line). + * DPI waits for fifo ready only for the first line of the first frame. + * If line is wider than fifo size, one can set watermark + * at fifo size, or set it to line size as watermark will be + * saturated at fifo size inside MCDE. + */ + switch (port->type) { + case MCDE_PORTTYPE_DSI: + if (port->mode == MCDE_PORTMODE_CMD) + /* Equivalent of ceil(disp_ppl/fifo_size) */ + return (disp_ppl - 1) / get_output_fifo_size(fifo) + 1; + else + return 1; + break; + case MCDE_PORTTYPE_DPI: + return 1; + break; + default: + break; + } + return 1; +} + +static void update_vid_horizontal_blanking(struct mcde_port *port, + struct mcde_video_mode *vmode, bool sync_is_pulse, u8 bpp) +{ + int hfp, hbp, hsa; + u8 link = port->link; + + /* + * vmode->hfp, vmode->hbp and vmode->hsw are given in pixels + * and must be re-calculated into bytes + * + * 6 + 2 is HFP header + checksum + */ + hfp = vmode->hfp * bpp - 6 - 2; + if (sync_is_pulse) { + /* + * 6 is HBP header + checksum + * 4 is RGB header + checksum + */ + hbp = vmode->hbp * bpp - 4 - 6; + /* + * 6 is HBP header + checksum + * 4 is HSW packet bytes + * 4 is RGB header + checksum + */ + hsa = vmode->hsw * bpp - 4 - 4 - 6; + } else { + /* + * 6 is HBP header + checksum + * 4 is HSW packet bytes + * 4 is RGB header + checksum + */ + hbp = (vmode->hbp + vmode->hsw) * bpp - 4 - 4 - 6; + /* HSA is not considered in this mode and set to 0 */ + hsa = 0; + } + if (hfp < 0) { + hfp = 0; + dev_warn(&mcde_dev->dev, + "%s: negative calc for hfp, set to 0\n", __func__); + } + if (hbp < 0) { + hbp = 0; + dev_warn(&mcde_dev->dev, + "%s: negative calc for hbp, set to 0\n", __func__); + } + if (hsa < 0) { + hsa = 0; + dev_warn(&mcde_dev->dev, + "%s: negative calc for hsa, set to 0\n", __func__); + } + + dsi_wfld(link, DSI_VID_HSIZE1, HFP_LENGTH, hfp); + dsi_wfld(link, DSI_VID_HSIZE1, HBP_LENGTH, hbp); + dsi_wfld(link, DSI_VID_HSIZE1, HSA_LENGTH, hsa); +} + +static void update_vid_frame_parameters(struct mcde_port *port, + struct mcde_video_mode *vmode, u8 bpp) +{ + u8 link = port->link; + bool burst_mode, sync_is_pulse, tvg_enable; + u32 hs_byte_clk, pck_len, blkline_pck, line_duration; + u32 blkeol_pck, blkeol_duration; + u8 pixel_mode; + u8 rgb_header; + + get_vid_operating_mode(port, &burst_mode, &sync_is_pulse, &tvg_enable); + + dsi_wfld(link, DSI_VID_VSIZE, VFP_LENGTH, vmode->vfp); + dsi_wfld(link, DSI_VID_VSIZE, VBP_LENGTH, vmode->vbp); + dsi_wfld(link, DSI_VID_VSIZE, VSA_LENGTH, vmode->vsw); + update_vid_horizontal_blanking(port, vmode, sync_is_pulse, bpp); + + dsi_wfld(link, DSI_VID_VSIZE, VACT_LENGTH, vmode->yres); + dsi_wfld(link, DSI_VID_HSIZE2, RGB_SIZE, vmode->xres * bpp); + + /* + * The rgb_header identifies the pixel stream format, + * as described in the MIPI DSI Specification: + * + * 0x0E: Packed pixel stream, 16-bit RGB, 565 format + * 0x1E: Packed pixel stream, 18-bit RGB, 666 format + * 0x2E: Loosely Packed pixel stream, 18-bit RGB, 666 format + * 0x3E: Packed pixel stream, 24-bit RGB, 888 format + */ + switch (port->pixel_format) { + case MCDE_PORTPIXFMT_DSI_16BPP: + pixel_mode = 0; + rgb_header = 0x0E; + break; + case MCDE_PORTPIXFMT_DSI_18BPP: + pixel_mode = 2; + rgb_header = 0x2E; + break; + case MCDE_PORTPIXFMT_DSI_18BPP_PACKED: + pixel_mode = 1; + rgb_header = 0x1E; + break; + case MCDE_PORTPIXFMT_DSI_24BPP: + pixel_mode = 3; + rgb_header = 0x3E; + break; + default: + pixel_mode = 3; + rgb_header = 0x3E; + dev_warn(&mcde_dev->dev, + "%s: invalid pixel format %d\n", + __func__, port->pixel_format); + break; + } + + dsi_wfld(link, DSI_VID_MAIN_CTL, VID_PIXEL_MODE, pixel_mode); + dsi_wfld(link, DSI_VID_MAIN_CTL, HEADER, rgb_header); + + if (tvg_enable) { + /* + * with these settings, expect to see 64 pixels wide + * red and green vertical stripes on the screen when + * tvg_enable = 1 + */ + dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, TVG_SEL, 1); + + dsi_wfld(link, DSI_TVG_CTL, TVG_STRIPE_SIZE, 6); + dsi_wfld(link, DSI_TVG_CTL, TVG_MODE, 2); + dsi_wfld(link, DSI_TVG_CTL, TVG_STOPMODE, 2); + dsi_wfld(link, DSI_TVG_CTL, TVG_RUN, 1); + + dsi_wfld(link, DSI_TVG_IMG_SIZE, TVG_NBLINE, vmode->yres); + dsi_wfld(link, DSI_TVG_IMG_SIZE, TVG_LINE_SIZE, + vmode->xres * bpp); + + dsi_wfld(link, DSI_TVG_COLOR1, COL1_BLUE, 0); + dsi_wfld(link, DSI_TVG_COLOR1, COL1_GREEN, 0); + dsi_wfld(link, DSI_TVG_COLOR1, COL1_RED, 0xFF); + + dsi_wfld(link, DSI_TVG_COLOR2, COL2_BLUE, 0); + dsi_wfld(link, DSI_TVG_COLOR2, COL2_GREEN, 0xFF); + dsi_wfld(link, DSI_TVG_COLOR2, COL2_RED, 0); + } + + /* + * vid->pixclock is the time between two pixels (in picoseconds) + * + * hs_byte_clk is the amount of transferred bytes per lane and + * second (in MHz) + */ + hs_byte_clk = 1000000 / vmode->pixclock / 8; + pck_len = 1000000 * hs_byte_clk / port->refresh_rate / + (vmode->vsw + vmode->vbp + vmode->yres + vmode->vfp) * + port->phy.dsi.num_data_lanes; + + /* + * 6 is header + checksum, header = 4 bytes, checksum = 2 bytes + * 4 is short packet for vsync/hsync + */ + if (sync_is_pulse) + blkline_pck = pck_len - vmode->hsw - 6; + else + blkline_pck = pck_len - 4 - 6; + + line_duration = (blkline_pck + 6) / port->phy.dsi.num_data_lanes; + blkeol_pck = pck_len - + (vmode->hsw + vmode->hbp + vmode->xres + vmode->hfp) * bpp - 6; + blkeol_duration = (blkeol_pck + 6) / port->phy.dsi.num_data_lanes; + + if (sync_is_pulse) + dsi_wfld(link, DSI_VID_BLKSIZE2, BLKLINE_PULSE_PCK, + blkline_pck); + else + dsi_wfld(link, DSI_VID_BLKSIZE1, BLKLINE_EVENT_PCK, + blkline_pck); + dsi_wfld(link, DSI_VID_DPHY_TIME, REG_LINE_DURATION, line_duration); + if (burst_mode) { + dsi_wfld(link, DSI_VID_BLKSIZE1, BLKEOL_PCK, blkeol_pck); + dsi_wfld(link, DSI_VID_PCK_TIME, BLKEOL_DURATION, + blkeol_duration); + dsi_wfld(link, DSI_VID_VCA_SETTING1, MAX_BURST_LIMIT, + blkeol_pck - 6); + dsi_wfld(link, DSI_VID_VCA_SETTING2, EXACT_BURST_LIMIT, + blkeol_pck); + } + if (sync_is_pulse) + dsi_wfld(link, DSI_VID_VCA_SETTING2, MAX_LINE_LIMIT, + blkline_pck - 6); +} + +void update_channel_registers(enum mcde_chnl chnl_id, struct chnl_regs *regs, + struct mcde_port *port, enum mcde_fifo fifo, + struct mcde_video_mode *video_mode) +{ + u8 idx = chnl_id; + u32 out_synch_src = MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_FORMATTER; + u32 src_synch = MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE; + u32 fifo_wtrmrk = 0; + + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + /* + * Select appropriate fifo watermark. + * Watermark will be saturated at fifo size inside MCDE. + */ + fifo_wtrmrk = video_mode->xres / + get_pkt_div(video_mode->xres, port, fifo); + + dev_vdbg(&mcde_dev->dev, "%s fifo_watermark=%d for chnl_id=%d\n", + __func__, fifo_wtrmrk, chnl_id); + + switch (chnl_id) { + case MCDE_CHNL_A: + mcde_wfld(MCDE_CTRLA, FIFOWTRMRK, fifo_wtrmrk); + break; + case MCDE_CHNL_B: + mcde_wfld(MCDE_CTRLB, FIFOWTRMRK, fifo_wtrmrk); + break; + case MCDE_CHNL_C0: + mcde_wfld(MCDE_CTRLC0, FIFOWTRMRK, fifo_wtrmrk); + break; + case MCDE_CHNL_C1: + mcde_wfld(MCDE_CTRLC1, FIFOWTRMRK, fifo_wtrmrk); + break; + default: + break; + } + + /* Channel */ + if (port->type == MCDE_PORTTYPE_DSI) { + if (port->update_auto_trig) { + switch (port->sync_src) { + case MCDE_SYNCSRC_TE0: + out_synch_src = + MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_TE0; + src_synch = + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE; + break; + case MCDE_SYNCSRC_OFF: + src_synch = + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE; + break; + case MCDE_SYNCSRC_TE1: + default: + out_synch_src = + MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_TE1; + src_synch = + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE; + break; + case MCDE_SYNCSRC_TE_POLLING: + src_synch = + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE; + break; + case MCDE_SYNCSRC_FORMATTER: + out_synch_src = + MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_FORMATTER; + src_synch = + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE; + break; + } + } else { + if (port->sync_src == MCDE_SYNCSRC_TE0) { + out_synch_src = + MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_TE0; + src_synch = + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE; + } + } + } else if (port->type == MCDE_PORTTYPE_DPI) { + src_synch = port->update_auto_trig ? + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE : + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE; + } + + mcde_wreg(MCDE_CHNL0CONF + idx * MCDE_CHNL0CONF_GROUPOFFSET, + MCDE_CHNL0CONF_PPL(regs->ppl-1) | + MCDE_CHNL0CONF_LPF(regs->lpf-1)); + mcde_wreg(MCDE_CHNL0STAT + idx * MCDE_CHNL0STAT_GROUPOFFSET, + MCDE_CHNL0STAT_CHNLBLBCKGND_EN(false) | + MCDE_CHNL0STAT_CHNLRD(true)); + mcde_wreg(MCDE_CHNL0SYNCHMOD + + idx * MCDE_CHNL0SYNCHMOD_GROUPOFFSET, + MCDE_CHNL0SYNCHMOD_SRC_SYNCH(src_synch) | + MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC(out_synch_src)); + mcde_wreg(MCDE_CHNL0BCKGNDCOL + idx * MCDE_CHNL0BCKGNDCOL_GROUPOFFSET, + MCDE_CHNL0BCKGNDCOL_B(0) | + MCDE_CHNL0BCKGNDCOL_G(0) | + MCDE_CHNL0BCKGNDCOL_R(0)); + + if (chnl_id == MCDE_CHNL_A || chnl_id == MCDE_CHNL_B) { + u32 mcde_crx1; + u32 mcde_pal0x; + u32 mcde_pal1x; + if (chnl_id == MCDE_CHNL_A) { + mcde_crx1 = MCDE_CRA1; + mcde_pal0x = MCDE_PAL0A; + mcde_pal1x = MCDE_PAL1A; + mcde_wfld(MCDE_CRA0, PALEN, regs->palette_enable); + } else { + mcde_crx1 = MCDE_CRB1; + mcde_pal0x = MCDE_PAL0B; + mcde_pal1x = MCDE_PAL1B; + mcde_wfld(MCDE_CRB0, PALEN, regs->palette_enable); + } + mcde_wreg(mcde_crx1, + MCDE_CRA1_PCD(regs->pcd) | + MCDE_CRA1_CLKSEL(regs->clksel) | + MCDE_CRA1_CDWIN(regs->cdwin) | + MCDE_CRA1_OUTBPP(bpp2outbpp(regs->bpp)) | + MCDE_CRA1_BCD(regs->bcd) | + MCDE_CRA1_CLKTYPE(regs->internal_clk)); + if (regs->palette_enable) { + int i; + for (i = 0; i < 256; i++) { + mcde_wreg(mcde_pal0x, + MCDE_PAL0A_GREEN(regs->map_g(i)) | + MCDE_PAL0A_BLUE(regs->map_b(i))); + mcde_wreg(mcde_pal1x, + MCDE_PAL1A_RED(regs->map_r(i))); + } + } + } + + /* Formatter */ + if (port->type == MCDE_PORTTYPE_DSI) { + u8 fidx; + u32 temp, packet; + /* pkt_div is used to avoid underflow in output fifo for + * large packets */ + u32 pkt_div = 1; + u32 dsi_delay0 = 0; + u32 screen_ppl, screen_lpf; + + fidx = get_dsi_formatter_id(port); + + screen_ppl = video_mode->xres; + screen_lpf = video_mode->yres; + + pkt_div = get_pkt_div(screen_ppl, port, fifo); + + if (video_mode->interlaced) + screen_lpf /= 2; + + /* pkt_delay_progressive = pixelclock * htot / + * (1E12 / 160E6) / pkt_div */ + dsi_delay0 = (video_mode->pixclock) * + (video_mode->xres + video_mode->hbp + + video_mode->hfp) / + (100000000 / ((mcde_clk_rate / 10000))) / pkt_div; + + if ((screen_ppl == SCREEN_PPL_CEA2) && + (screen_lpf == SCREEN_LPF_CEA2)) + dsi_delay0 += DSI_DELAY0_CEA2_ADD; + + temp = mcde_rreg(MCDE_DSIVID0CONF0 + + fidx * MCDE_DSIVID0CONF0_GROUPOFFSET); + mcde_wreg(MCDE_DSIVID0CONF0 + + fidx * MCDE_DSIVID0CONF0_GROUPOFFSET, + (temp & ~MCDE_DSIVID0CONF0_PACKING_MASK) | + MCDE_DSIVID0CONF0_PACKING(regs->dsipacking)); + /* no extra command byte in video mode */ + if (port->mode == MCDE_PORTMODE_CMD) + packet = ((screen_ppl / pkt_div * regs->bpp) >> 3) + 1; + else + packet = ((screen_ppl / pkt_div * regs->bpp) >> 3); + mcde_wreg(MCDE_DSIVID0FRAME + + fidx * MCDE_DSIVID0FRAME_GROUPOFFSET, + MCDE_DSIVID0FRAME_FRAME(packet * pkt_div * screen_lpf)); + mcde_wreg(MCDE_DSIVID0PKT + fidx * MCDE_DSIVID0PKT_GROUPOFFSET, + MCDE_DSIVID0PKT_PACKET(packet)); + mcde_wreg(MCDE_DSIVID0SYNC + + fidx * MCDE_DSIVID0SYNC_GROUPOFFSET, + MCDE_DSIVID0SYNC_SW(0) | + MCDE_DSIVID0SYNC_DMA(0)); + mcde_wreg(MCDE_DSIVID0CMDW + + fidx * MCDE_DSIVID0CMDW_GROUPOFFSET, + MCDE_DSIVID0CMDW_CMDW_START(DCS_CMD_WRITE_START) | + MCDE_DSIVID0CMDW_CMDW_CONTINUE(DCS_CMD_WRITE_CONTINUE)); + mcde_wreg(MCDE_DSIVID0DELAY0 + + fidx * MCDE_DSIVID0DELAY0_GROUPOFFSET, + MCDE_DSIVID0DELAY0_INTPKTDEL(dsi_delay0)); + mcde_wreg(MCDE_DSIVID0DELAY1 + + fidx * MCDE_DSIVID0DELAY1_GROUPOFFSET, + MCDE_DSIVID0DELAY1_TEREQDEL(0) | + MCDE_DSIVID0DELAY1_FRAMESTARTDEL(0)); + + if (port->mode == MCDE_PORTMODE_VID) + update_vid_frame_parameters(port, video_mode, + regs->bpp / 8); + } else if (port->type == MCDE_PORTTYPE_DPI && + !port->phy.dpi.tv_mode) { + /* DPI LCD Mode */ + if (chnl_id == MCDE_CHNL_A) { + mcde_wreg(MCDE_SYNCHCONFA, + MCDE_SYNCHCONFA_HWREQVEVENT_ENUM( + ACTIVE_VIDEO) | + MCDE_SYNCHCONFA_HWREQVCNT( + video_mode->yres - 1) | + MCDE_SYNCHCONFA_SWINTVEVENT_ENUM( + ACTIVE_VIDEO) | + MCDE_SYNCHCONFA_SWINTVCNT( + video_mode->yres - 1)); + } else if (chnl_id == MCDE_CHNL_B) { + mcde_wreg(MCDE_SYNCHCONFB, + MCDE_SYNCHCONFB_HWREQVEVENT_ENUM( + ACTIVE_VIDEO) | + MCDE_SYNCHCONFB_HWREQVCNT( + video_mode->yres - 1) | + MCDE_SYNCHCONFB_SWINTVEVENT_ENUM( + ACTIVE_VIDEO) | + MCDE_SYNCHCONFB_SWINTVCNT( + video_mode->yres - 1)); + } + } + + if (regs->roten) { + mcde_wreg(MCDE_ROTADD0A + chnl_id * MCDE_ROTADD0A_GROUPOFFSET, + regs->rotbuf1); + mcde_wreg(MCDE_ROTADD1A + chnl_id * MCDE_ROTADD1A_GROUPOFFSET, + regs->rotbuf2); + mcde_wreg(MCDE_ROTACONF + chnl_id * MCDE_ROTACONF_GROUPOFFSET, + MCDE_ROTACONF_ROTBURSTSIZE_ENUM(HW_8W) | + MCDE_ROTACONF_ROTDIR(regs->rotdir) | + MCDE_ROTACONF_STRIP_WIDTH_ENUM(16PIX) | + MCDE_ROTACONF_RD_MAXOUT_ENUM(4_REQ) | + MCDE_ROTACONF_WR_MAXOUT_ENUM(8_REQ)); + } + + /* Blending */ + if (chnl_id == MCDE_CHNL_A) { + mcde_wfld(MCDE_CRA0, BLENDEN, regs->blend_en); + mcde_wfld(MCDE_CRA0, BLENDCTRL, regs->blend_ctrl); + mcde_wfld(MCDE_CRA0, ALPHABLEND, regs->alpha_blend); + } else if (chnl_id == MCDE_CHNL_B) { + mcde_wfld(MCDE_CRB0, BLENDEN, regs->blend_en); + mcde_wfld(MCDE_CRB0, BLENDCTRL, regs->blend_ctrl); + mcde_wfld(MCDE_CRB0, ALPHABLEND, regs->alpha_blend); + } + + dev_vdbg(&mcde_dev->dev, "Channel registers setup, chnl=%d\n", chnl_id); + regs->dirty = false; +} + +static int enable_mcde_hw(void) +{ + int ret; + int i; + + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + cancel_delayed_work(&hw_timeout_work); + schedule_delayed_work(&hw_timeout_work, + msecs_to_jiffies(MCDE_SLEEP_WATCHDOG)); + + for (i = 0; i < num_channels; i++) { + struct mcde_chnl_state *chnl = &channels[i]; + if (chnl->state == CHNLSTATE_SUSPEND) { + /* Mark all registers as dirty */ + set_channel_state_atomic(chnl, CHNLSTATE_IDLE); + chnl->ovly0->regs.dirty = true; + chnl->ovly0->regs.dirty_buf = true; + if (chnl->ovly1) { + chnl->ovly1->regs.dirty = true; + chnl->ovly1->regs.dirty_buf = true; + } + chnl->regs.dirty = true; + chnl->col_regs.dirty = true; + chnl->tv_regs.dirty = true; + atomic_set(&chnl->vcmp_cnt, 0); + } + } + + if (mcde_is_enabled) { + dev_vdbg(&mcde_dev->dev, "%s - already enabled\n", __func__); + return 0; + } + + enable_clocks_and_power(mcde_dev); + + ret = request_irq(mcde_irq, mcde_irq_handler, 0, "mcde", + &mcde_dev->dev); + if (ret) { + dev_dbg(&mcde_dev->dev, "Failed to request irq (irq=%d)\n", + mcde_irq); + cancel_delayed_work(&hw_timeout_work); + return -EINVAL; + } + + update_mcde_registers(); + + dev_vdbg(&mcde_dev->dev, "%s - enable done\n", __func__); + + mcde_is_enabled = true; + return 0; +} + +/* DSI */ +static int mcde_dsi_direct_cmd_write(struct mcde_chnl_state *chnl, + bool dcs, u8 cmd, u8 *data, int len) +{ + int i, ret = 0; + u32 wrdat[4] = { 0, 0, 0, 0 }; + u32 settings; + u8 link = chnl->port.link; + u8 virt_id = chnl->port.phy.dsi.virt_id; + u32 counter = DSI_WRITE_CMD_TIMEOUT; + + if (len > MCDE_MAX_DSI_DIRECT_CMD_WRITE || + chnl->port.type != MCDE_PORTTYPE_DSI) + return -EINVAL; + + mcde_lock(__func__, __LINE__); + + _mcde_chnl_enable(chnl); + if (enable_mcde_hw()) { + mcde_unlock(__func__, __LINE__); + return -EINVAL; + } + if (!chnl->formatter_updated) + (void)update_channel_static_registers(chnl); + + set_channel_state_sync(chnl, CHNLSTATE_DSI_WRITE); + + if (dcs) { + wrdat[0] = cmd; + for (i = 1; i <= len; i++) + wrdat[i>>2] |= ((u32)data[i-1] << ((i & 3) * 8)); + } else { + /* no explicit cmd byte for generic_write, only params */ + for (i = 0; i < len; i++) + wrdat[i>>2] |= ((u32)data[i] << ((i & 3) * 8)); + } + + settings = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_ENUM(WRITE) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT(len > 1) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID(virt_id) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE(len+1) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN(true); + if (dcs) { + if (len == 0) + settings |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM( + DCS_SHORT_WRITE_0); + else if (len == 1) + settings |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM( + DCS_SHORT_WRITE_1); + else + settings |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM( + DCS_LONG_WRITE); + } else { + if (len == 0) + settings |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM( + GENERIC_SHORT_WRITE_0); + else if (len == 1) + settings |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM( + GENERIC_SHORT_WRITE_1); + else if (len == 2) + settings |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM( + GENERIC_SHORT_WRITE_2); + else + settings |= DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM( + GENERIC_LONG_WRITE); + } + + dsi_wreg(link, DSI_DIRECT_CMD_MAIN_SETTINGS, settings); + dsi_wreg(link, DSI_DIRECT_CMD_WRDAT0, wrdat[0]); + if (len > 3) + dsi_wreg(link, DSI_DIRECT_CMD_WRDAT1, wrdat[1]); + if (len > 7) + dsi_wreg(link, DSI_DIRECT_CMD_WRDAT2, wrdat[2]); + if (len > 11) + dsi_wreg(link, DSI_DIRECT_CMD_WRDAT3, wrdat[3]); + dsi_wreg(link, DSI_DIRECT_CMD_STS_CLR, ~0); + dsi_wreg(link, DSI_CMD_MODE_STS_CLR, ~0); + dsi_wreg(link, DSI_DIRECT_CMD_SEND, true); + + /* loop will normally run zero or one time until WRITE_COMPLETED */ + while (!dsi_rfld(link, DSI_DIRECT_CMD_STS, WRITE_COMPLETED) + && --counter) + cpu_relax(); + + if (!counter) { + dev_err(&mcde_dev->dev, + "%s: DSI write cmd 0x%x timeout on DSI link %u!\n", + __func__, cmd, link); + ret = -ETIME; + } else { + /* inform if >100 loops before command completion */ + if (counter < (DSI_WRITE_CMD_TIMEOUT-DSI_WRITE_CMD_TIMEOUT/10)) + dev_vdbg(&mcde_dev->dev, + "%s: %u loops for DSI command %x completion\n", + __func__, (DSI_WRITE_CMD_TIMEOUT - counter), + cmd); + + dev_vdbg(&mcde_dev->dev, "DSI Write ok %x error %x\n", + dsi_rreg(link, DSI_DIRECT_CMD_STS_FLAG), + dsi_rreg(link, DSI_CMD_MODE_STS_FLAG)); + } + + set_channel_state_atomic(chnl, CHNLSTATE_IDLE); + + mcde_unlock(__func__, __LINE__); + + return ret; +} + +int mcde_dsi_generic_write(struct mcde_chnl_state *chnl, u8* para, int len) +{ + return mcde_dsi_direct_cmd_write(chnl, false, 0, para, len); +} + +int mcde_dsi_dcs_write(struct mcde_chnl_state *chnl, u8 cmd, u8* data, int len) +{ + return mcde_dsi_direct_cmd_write(chnl, true, cmd, data, len); +} + +int mcde_dsi_dcs_read(struct mcde_chnl_state *chnl, + u8 cmd, u32 *data, int *len) +{ + int ret = 0; + u8 link = chnl->port.link; + u8 virt_id = chnl->port.phy.dsi.virt_id; + u32 settings; + bool ok = false; + bool error, ack_with_err; + u8 nbr_of_retries = DSI_READ_NBR_OF_RETRIES; + + if (*len > MCDE_MAX_DCS_READ || chnl->port.type != MCDE_PORTTYPE_DSI) + return -EINVAL; + + mcde_lock(__func__, __LINE__); + + _mcde_chnl_enable(chnl); + if (enable_mcde_hw()) { + mcde_unlock(__func__, __LINE__); + return -EINVAL; + } + if (!chnl->formatter_updated) + (void)update_channel_static_registers(chnl); + + set_channel_state_sync(chnl, CHNLSTATE_DSI_READ); + + dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, BTA_EN, true); + dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, READ_EN, true); + settings = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_ENUM(READ) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT(false) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID(virt_id) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE(1) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN(true) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM(DCS_READ); + dsi_wreg(link, DSI_DIRECT_CMD_MAIN_SETTINGS, settings); + dsi_wreg(link, DSI_DIRECT_CMD_WRDAT0, cmd); + + do { + u8 wait = DSI_READ_TIMEOUT; + dsi_wreg(link, DSI_DIRECT_CMD_STS_CLR, ~0); + dsi_wreg(link, DSI_DIRECT_CMD_RD_STS_CLR, ~0); + dsi_wreg(link, DSI_DIRECT_CMD_SEND, true); + + while (wait-- && !(error = dsi_rfld(link, DSI_DIRECT_CMD_STS, + READ_COMPLETED_WITH_ERR)) && + !(ok = dsi_rfld(link, DSI_DIRECT_CMD_STS, + READ_COMPLETED))) + udelay(DSI_READ_DELAY); + + ack_with_err = dsi_rfld(link, DSI_DIRECT_CMD_STS, + ACKNOWLEDGE_WITH_ERR_RECEIVED); + if (ack_with_err) + dev_warn(&mcde_dev->dev, + "DCS Acknowledge Error Report %.4X\n", + dsi_rfld(link, DSI_DIRECT_CMD_STS, ACK_VAL)); + } while (--nbr_of_retries && ack_with_err); + + if (ok) { + int rdsize; + u32 rddat; + + rdsize = dsi_rfld(link, DSI_DIRECT_CMD_RD_PROPERTY, RD_SIZE); + rddat = dsi_rreg(link, DSI_DIRECT_CMD_RDDAT); + if (rdsize < *len) + dev_warn(&mcde_dev->dev, "DCS incomplete read %d<%d" + " (%.8X)\n", rdsize, *len, rddat); + *len = min(*len, rdsize); + memcpy(data, &rddat, *len); + } else { + dev_err(&mcde_dev->dev, "DCS read failed, err=%d, sts=%X\n", + error, dsi_rreg(link, DSI_DIRECT_CMD_STS)); + ret = -EIO; + } + + dsi_wreg(link, DSI_CMD_MODE_STS_CLR, ~0); + dsi_wreg(link, DSI_DIRECT_CMD_STS_CLR, ~0); + + set_channel_state_atomic(chnl, CHNLSTATE_IDLE); + + mcde_unlock(__func__, __LINE__); + + return ret; +} + +/* + * Set Maximum Return Packet size is a command that specifies the + * maximum size of the payload transmitted from peripheral back to + * the host processor. + * + * During power-on or reset sequence, the Maximum Return Packet Size + * is set to a default value of one. In order to be able to use + * mcde_dsi_dcs_read for reading more than 1 byte at a time, this + * parameter should be set by the host processor to the desired value + * in the initialization routine before commencing normal operation. + */ +int mcde_dsi_set_max_pkt_size(struct mcde_chnl_state *chnl) +{ + u32 settings; + u8 link = chnl->port.link; + u8 virt_id = chnl->port.phy.dsi.virt_id; + + if (chnl->port.type != MCDE_PORTTYPE_DSI) + return -EINVAL; + + mcde_lock(__func__, __LINE__); + + if (enable_mcde_hw()) { + mcde_unlock(__func__, __LINE__); + return -EIO; + } + + set_channel_state_sync(chnl, CHNLSTATE_DSI_WRITE); + + /* + * Set Maximum Return Packet Size is a two-byte command packet + * that specifies the maximum size of the payload as u16 value. + * The order of bytes is: MaxSize LSB, MaxSize MSB + */ + settings = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_ENUM(WRITE) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT(false) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID(virt_id) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE(2) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN(true) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM( + SET_MAX_PKT_SIZE); + dsi_wreg(link, DSI_DIRECT_CMD_MAIN_SETTINGS, settings); + dsi_wreg(link, DSI_DIRECT_CMD_WRDAT0, MCDE_MAX_DCS_READ); + dsi_wreg(link, DSI_DIRECT_CMD_SEND, true); + + set_channel_state_atomic(chnl, CHNLSTATE_IDLE); + + mcde_unlock(__func__, __LINE__); + + return 0; +} + +static void dsi_te_poll_req(struct mcde_chnl_state *chnl) +{ + u8 lnk = chnl->port.link; + const struct mcde_port *port = &chnl->port; + + dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, REG_TE_EN, false); + if (port->ifc == 0) + dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, IF1_TE_EN, true); + if (port->ifc == 1) + dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, IF2_TE_EN, true); + dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, BTA_EN, true); + dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, READ_EN, true); + dsi_wfld(lnk, DSI_CMD_MODE_CTL, TE_TIMEOUT, 0x3FF); + dsi_wfld(lnk, DSI_MCTL_MAIN_DATA_CTL, TE_POLLING_EN, true); +} + +static void dsi_te_poll_set_timer(struct mcde_chnl_state *chnl, + unsigned int timeout) +{ + mod_timer(&chnl->dsi_te_timer, + jiffies + + msecs_to_jiffies(timeout)); +} + +static void dsi_te_timer_function(unsigned long arg) +{ + struct mcde_chnl_state *chnl; + u8 lnk; + + if (arg >= num_channels) { + dev_err(&mcde_dev->dev, "%s invalid arg:%ld\n", __func__, arg); + return; + } + + chnl = &channels[arg]; + + if (mcde_is_enabled && chnl->enabled && chnl->formatter_updated) { + lnk = chnl->port.link; + /* No TE answer; force stop */ + dsi_wfld(lnk, DSI_MCTL_MAIN_PHY_CTL, FORCE_STOP_MODE, true); + udelay(20); + dsi_wfld(lnk, DSI_MCTL_MAIN_PHY_CTL, FORCE_STOP_MODE, false); + dev_info(&mcde_dev->dev, "DSI%d force stop\n", lnk); + dsi_te_poll_set_timer(chnl, DSI_TE_NO_ANSWER_TIMEOUT); + } else { + dev_info(&mcde_dev->dev, "1:DSI force stop\n"); + } +} + +static void dsi_te_request(struct mcde_chnl_state *chnl) +{ + u8 link = chnl->port.link; + u8 virt_id = chnl->port.phy.dsi.virt_id; + u32 settings; + + dev_vdbg(&mcde_dev->dev, "Request BTA TE, chnl=%d\n", + chnl->id); + + set_channel_state_atomic(chnl, CHNLSTATE_WAIT_TE); + + dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, BTA_EN, true); + dsi_wfld(link, DSI_MCTL_MAIN_DATA_CTL, REG_TE_EN, true); + dsi_wfld(link, DSI_CMD_MODE_CTL, TE_TIMEOUT, 0x3FF); + settings = DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_NAT_ENUM(TE_REQ) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LONGNOTSHORT(false) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_ID(virt_id) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_SIZE(2) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_LP_EN(true) | + DSI_DIRECT_CMD_MAIN_SETTINGS_CMD_HEAD_ENUM(DCS_SHORT_WRITE_1); + dsi_wreg(link, DSI_DIRECT_CMD_MAIN_SETTINGS, settings); + dsi_wreg(link, DSI_DIRECT_CMD_WRDAT0, DCS_CMD_SET_TEAR_ON); + dsi_wreg(link, DSI_DIRECT_CMD_STS_CLR, + DSI_DIRECT_CMD_STS_CLR_TE_RECEIVED_CLR(true)); + dsi_wfld(link, DSI_DIRECT_CMD_STS_CTL, TE_RECEIVED_EN, true); + dsi_wreg(link, DSI_CMD_MODE_STS_CLR, + DSI_CMD_MODE_STS_CLR_ERR_NO_TE_CLR(true)); + dsi_wfld(link, DSI_CMD_MODE_STS_CTL, ERR_NO_TE_EN, true); + dsi_wreg(link, DSI_DIRECT_CMD_SEND, true); +} + +/* MCDE channels */ +static struct mcde_chnl_state *_mcde_chnl_get(enum mcde_chnl chnl_id, + enum mcde_fifo fifo, const struct mcde_port *port) +{ + int i; + struct mcde_chnl_state *chnl = NULL; + + static struct mcde_col_transform ycbcr_2_rgb = { + /* Note that in MCDE YUV 422 pixels come as VYU pixels */ + .matrix = { + {0xff30, 0x012a, 0xff9c}, + {0x0000, 0x012a, 0x0204}, + {0x0199, 0x012a, 0x0000}, + }, + .offset = {0x0088, 0xfeeb, 0xff21}, + }; + + static struct mcde_col_transform rgb_2_ycbcr = { + .matrix = { + {0x0042, 0x0081, 0x0019}, + {0xffda, 0xffb6, 0x0070}, + {0x0070, 0xffa2, 0xffee}, + }, + .offset = {0x0010, 0x0080, 0x0080}, + }; + + /* Allocate channel */ + for (i = 0; i < num_channels; i++) { + if (chnl_id == channels[i].id) + chnl = &channels[i]; + } + if (!chnl) { + dev_dbg(&mcde_dev->dev, "Invalid channel, chnl=%d\n", chnl_id); + return ERR_PTR(-EINVAL); + } + if (chnl->reserved) { + dev_dbg(&mcde_dev->dev, "Channel in use, chnl=%d\n", chnl_id); + return ERR_PTR(-EBUSY); + } + + chnl->port = *port; + chnl->fifo = fifo; + chnl->formatter_updated = false; + chnl->ycbcr_2_rgb = ycbcr_2_rgb; + chnl->rgb_2_ycbcr = rgb_2_ycbcr; + + chnl->blend_en = true; + chnl->blend_ctrl = MCDE_CRA0_BLENDCTRL_SOURCE; + chnl->alpha_blend = 0xFF; + + _mcde_chnl_apply(chnl); + chnl->reserved = true; + + if (chnl->port.type == MCDE_PORTTYPE_DPI) { + chnl->clk_dpi = clk_get(&mcde_dev->dev, CLK_DPI); + if (chnl->port.phy.dpi.tv_mode) + chnl->vcmp_per_field = true; + } else if (chnl->port.type == MCDE_PORTTYPE_DSI && + dsi_use_clk_framework) { + char dsihs_name[10]; + char dsilp_name[10]; + + sprintf(dsihs_name, "dsihs%d", port->link); + sprintf(dsilp_name, "dsilp%d", port->link); + + chnl->clk_dsi_lp = clk_get(&mcde_dev->dev, dsilp_name); + chnl->clk_dsi_hs = clk_get(&mcde_dev->dev, dsihs_name); + if (port->phy.dsi.lp_freq != clk_round_rate(chnl->clk_dsi_lp, + port->phy.dsi.lp_freq)) + dev_warn(&mcde_dev->dev, "Could not set dsi lp freq" + " to %d\n", port->phy.dsi.lp_freq); + WARN_ON_ONCE(clk_set_rate(chnl->clk_dsi_lp, + port->phy.dsi.lp_freq)); + if (port->phy.dsi.hs_freq != clk_round_rate(chnl->clk_dsi_hs, + port->phy.dsi.hs_freq)) + dev_warn(&mcde_dev->dev, "Could not set dsi hs freq" + " to %d\n", port->phy.dsi.hs_freq); + WARN_ON_ONCE(clk_set_rate(chnl->clk_dsi_hs, + port->phy.dsi.hs_freq)); + } + return chnl; +} + +static int _mcde_chnl_apply(struct mcde_chnl_state *chnl) +{ + bool roten = false; + u8 rotdir = 0; + + if (chnl->rotation == MCDE_DISPLAY_ROT_90_CCW) { + roten = true; + rotdir = MCDE_ROTACONF_ROTDIR_CCW; + } else if (chnl->rotation == MCDE_DISPLAY_ROT_90_CW) { + roten = true; + rotdir = MCDE_ROTACONF_ROTDIR_CW; + } + /* REVIEW: 180 deg? */ + + chnl->regs.bpp = portfmt2bpp(chnl->port.pixel_format); + chnl->regs.synchronized_update = chnl->synchronized_update; + chnl->regs.roten = roten; + chnl->regs.rotdir = rotdir; + chnl->regs.rotbuf1 = chnl->rotbuf1; + chnl->regs.rotbuf2 = chnl->rotbuf2; + chnl->regs.palette_enable = chnl->palette_enable; + chnl->regs.map_r = chnl->map_r; + chnl->regs.map_g = chnl->map_g; + chnl->regs.map_b = chnl->map_b; + if (chnl->port.type == MCDE_PORTTYPE_DSI) { + chnl->regs.clksel = MCDE_CRA1_CLKSEL_MCDECLK; + chnl->regs.dsipacking = + portfmt2dsipacking(chnl->port.pixel_format); + } else if (chnl->port.type == MCDE_PORTTYPE_DPI) { + if (chnl->port.phy.dpi.tv_mode) { + chnl->regs.internal_clk = false; + chnl->regs.bcd = true; + if (chnl->id == MCDE_CHNL_A) + chnl->regs.clksel = MCDE_CRA1_CLKSEL_TV1CLK; + else + chnl->regs.clksel = MCDE_CRA1_CLKSEL_TV2CLK; + } else { + chnl->regs.internal_clk = true; + chnl->regs.clksel = MCDE_CRA1_CLKSEL_CLKPLL72; + chnl->regs.cdwin = + portfmt2cdwin(chnl->port.pixel_format); + chnl->regs.bcd = (chnl->port.phy.dpi.clock_div < 2); + if (!chnl->regs.bcd) + chnl->regs.pcd = + chnl->port.phy.dpi.clock_div - 2; + } + dpi_video_mode_apply(chnl); + } + + chnl->regs.blend_ctrl = chnl->blend_ctrl; + chnl->regs.blend_en = chnl->blend_en; + chnl->regs.alpha_blend = chnl->alpha_blend; + + chnl->regs.dirty = true; + + dev_vdbg(&mcde_dev->dev, "Channel applied, chnl=%d\n", chnl->id); + return 0; +} + +static void setup_channel(struct mcde_chnl_state *chnl) +{ + set_channel_state_sync(chnl, CHNLSTATE_SETUP); + + if (chnl->port.type == MCDE_PORTTYPE_DPI && chnl->tv_regs.dirty) + update_dpi_registers(chnl->id, &chnl->tv_regs); + if ((chnl->id == MCDE_CHNL_A || chnl->id == MCDE_CHNL_B) && + chnl->col_regs.dirty) + update_col_registers(chnl->id, &chnl->col_regs); + if (chnl->regs.dirty) + update_channel_registers(chnl->id, &chnl->regs, &chnl->port, + chnl->fifo, &chnl->vmode); +} + +static void chnl_update_continous(struct mcde_chnl_state *chnl, + bool tripple_buffer) +{ + if (chnl->state == CHNLSTATE_RUNNING) { + if (!tripple_buffer) + wait_for_vcmp(chnl); + return; + } + + setup_channel(chnl); + if (chnl->port.sync_src == MCDE_SYNCSRC_TE0) { + mcde_wfld(MCDE_CRC, SYCEN0, true); + } else if (chnl->port.sync_src == MCDE_SYNCSRC_TE1) { + mcde_wfld(MCDE_VSCRC1, VSSEL, 1); + mcde_wfld(MCDE_CRC, SYCEN1, true); + } + + enable_flow(chnl); +} + +static void chnl_update_non_continous(struct mcde_chnl_state *chnl) +{ + /* Commit settings to registers */ + setup_channel(chnl); + + if (chnl->regs.synchronized_update && + chnl->power_mode == MCDE_DISPLAY_PM_ON) { + if (chnl->port.type == MCDE_PORTTYPE_DSI && + chnl->port.sync_src == MCDE_SYNCSRC_BTA) + dsi_te_request(chnl); + } else { + do_softwaretrig(chnl); + dev_vdbg(&mcde_dev->dev, "Channel update (no sync), chnl=%d\n", + chnl->id); + } +} + +static void chnl_update_overlay(struct mcde_chnl_state *chnl, + struct mcde_ovly_state *ovly) +{ + if (!ovly) + return; + + if (ovly->regs.dirty_buf) { + if (!chnl->port.update_auto_trig) + set_channel_state_sync(chnl, CHNLSTATE_SETUP); + update_overlay_registers_on_the_fly(ovly->idx, &ovly->regs); + mcde_debugfs_overlay_update(chnl->id, ovly != chnl->ovly0); + } + if (ovly->regs.dirty) { + if (!chnl->port.update_auto_trig) + set_channel_state_sync(chnl, CHNLSTATE_SETUP); + chnl_ovly_pixel_format_apply(chnl, ovly); + update_overlay_registers(ovly->idx, &ovly->regs, &chnl->port, + chnl->fifo, chnl->regs.x, chnl->regs.y, + chnl->regs.ppl, chnl->regs.lpf, ovly->stride, + chnl->vmode.interlaced, chnl->rotation); + if (chnl->id == MCDE_CHNL_A || chnl->id == MCDE_CHNL_B) + update_col_registers(chnl->id, &chnl->col_regs); + } +} + +static int _mcde_chnl_update(struct mcde_chnl_state *chnl, + struct mcde_rectangle *update_area, + bool tripple_buffer) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + /* TODO: lock & make wait->trig async */ + if (!chnl->enabled || !update_area + || (update_area->w == 0 && update_area->h == 0)) { + return -EINVAL; + } + + if (chnl->port.update_auto_trig && tripple_buffer) + wait_for_vcmp(chnl); + + chnl->regs.x = update_area->x; + chnl->regs.y = update_area->y; + /* TODO Crop against video_mode.xres and video_mode.yres */ + chnl->regs.ppl = update_area->w; + chnl->regs.lpf = update_area->h; + if (chnl->port.type == MCDE_PORTTYPE_DPI && + chnl->port.phy.dpi.tv_mode) { + /* subtract border */ + chnl->regs.ppl -= chnl->tv_regs.dho + chnl->tv_regs.alw; + /* subtract double borders, ie. for both fields */ + chnl->regs.lpf -= 2 * (chnl->tv_regs.dvo + chnl->tv_regs.bsl); + } else if (chnl->port.type == MCDE_PORTTYPE_DSI && + chnl->vmode.interlaced) + chnl->regs.lpf /= 2; + + chnl_update_overlay(chnl, chnl->ovly0); + chnl_update_overlay(chnl, chnl->ovly1); + + if (chnl->port.update_auto_trig) + chnl_update_continous(chnl, tripple_buffer); + else + chnl_update_non_continous(chnl); + + dev_vdbg(&mcde_dev->dev, "Channel updated, chnl=%d\n", chnl->id); + mcde_debugfs_channel_update(chnl->id); + return 0; +} + +static int _mcde_chnl_enable(struct mcde_chnl_state *chnl) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + chnl->enabled = true; + return 0; +} + +/* API entry points */ +/* MCDE channels */ +struct mcde_chnl_state *mcde_chnl_get(enum mcde_chnl chnl_id, + enum mcde_fifo fifo, const struct mcde_port *port) +{ + struct mcde_chnl_state *chnl; + + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + chnl = _mcde_chnl_get(chnl_id, fifo, port); + dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__); + + return chnl; +} + +int mcde_chnl_set_pixel_format(struct mcde_chnl_state *chnl, + enum mcde_port_pix_fmt pix_fmt) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (!chnl->reserved) + return -EINVAL; + chnl->port.pixel_format = pix_fmt; + + dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__); + + return 0; +} + +int mcde_chnl_set_palette(struct mcde_chnl_state *chnl, + struct mcde_palette_table *palette) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (!chnl->reserved) + return -EINVAL; + if (palette != NULL) { + chnl->map_r = palette->map_col_ch0; + chnl->map_g = palette->map_col_ch1; + chnl->map_b = palette->map_col_ch2; + chnl->palette_enable = true; + } else { + chnl->map_r = NULL; + chnl->map_g = NULL; + chnl->map_b = NULL; + chnl->palette_enable = false; + } + + dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__); + return 0; +} + +void mcde_chnl_set_col_convert(struct mcde_chnl_state *chnl, + struct mcde_col_transform *transform, + enum mcde_col_convert convert) +{ + switch (convert) { + case MCDE_CONVERT_RGB_2_YCBCR: + memcpy(&chnl->rgb_2_ycbcr, transform, + sizeof(struct mcde_col_transform)); + /* force update: */ + if (chnl->transform == &chnl->rgb_2_ycbcr) { + chnl->transform = NULL; + chnl->ovly0->dirty = true; + chnl->ovly1->dirty = true; + } + break; + case MCDE_CONVERT_YCBCR_2_RGB: + memcpy(&chnl->ycbcr_2_rgb, transform, + sizeof(struct mcde_col_transform)); + /* force update: */ + if (chnl->transform == &chnl->ycbcr_2_rgb) { + chnl->transform = NULL; + chnl->ovly0->dirty = true; + chnl->ovly1->dirty = true; + } + break; + default: + /* Trivial transforms are handled internally */ + dev_warn(&mcde_dev->dev, + "%s: unsupported col convert\n", __func__); + break; + } +} + +int mcde_chnl_set_video_mode(struct mcde_chnl_state *chnl, + struct mcde_video_mode *vmode) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (chnl == NULL || vmode == NULL) + return -EINVAL; + + chnl->vmode = *vmode; + + chnl->ovly0->dirty = true; + if (chnl->ovly1) + chnl->ovly1->dirty = true; + + dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__); + + return 0; +} +EXPORT_SYMBOL(mcde_chnl_set_video_mode); + +int mcde_chnl_set_rotation(struct mcde_chnl_state *chnl, + enum mcde_display_rotation rotation, u32 rotbuf1, u32 rotbuf2) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (!chnl->reserved) + return -EINVAL; + + if (chnl->id != MCDE_CHNL_A && chnl->id != MCDE_CHNL_B) + return -EINVAL; + + chnl->rotation = rotation; + chnl->rotbuf1 = rotbuf1; + chnl->rotbuf2 = rotbuf2; + + dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__); + + return 0; +} + +int mcde_chnl_enable_synchronized_update(struct mcde_chnl_state *chnl, + bool enable) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + if (!chnl->reserved) + return -EINVAL; + + chnl->synchronized_update = enable; + + dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__); + + return 0; +} + +int mcde_chnl_set_power_mode(struct mcde_chnl_state *chnl, + enum mcde_display_power_mode power_mode) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (!chnl->reserved) + return -EINVAL; + + chnl->power_mode = power_mode; + + dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__); + + return 0; +} + +int mcde_chnl_apply(struct mcde_chnl_state *chnl) +{ + int ret ; + + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (!chnl->reserved) + return -EINVAL; + + mcde_lock(__func__, __LINE__); + ret = _mcde_chnl_apply(chnl); + mcde_unlock(__func__, __LINE__); + + dev_vdbg(&mcde_dev->dev, "%s exit with ret %d\n", __func__, ret); + + return ret; +} + +int mcde_chnl_update(struct mcde_chnl_state *chnl, + struct mcde_rectangle *update_area, + bool tripple_buffer) +{ + int ret; + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (!chnl->reserved) + return -EINVAL; + + mcde_lock(__func__, __LINE__); + enable_mcde_hw(); + if (!chnl->formatter_updated) + (void)update_channel_static_registers(chnl); + + if (chnl->regs.roten && !chnl->esram_is_enabled) { + WARN_ON_ONCE(regulator_enable(regulator_esram_epod)); + chnl->esram_is_enabled = true; + } + + ret = _mcde_chnl_update(chnl, update_area, tripple_buffer); + + mcde_unlock(__func__, __LINE__); + + dev_vdbg(&mcde_dev->dev, "%s exit with ret %d\n", __func__, ret); + + return ret; +} + +void mcde_chnl_put(struct mcde_chnl_state *chnl) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (chnl->enabled) { + stop_channel(chnl); + cancel_delayed_work(&hw_timeout_work); + disable_mcde_hw(false, true); + chnl->enabled = false; + } + + chnl->reserved = false; + if (chnl->port.type == MCDE_PORTTYPE_DPI) { + clk_put(chnl->clk_dpi); + if (chnl->port.phy.dpi.tv_mode) { + chnl->vcmp_per_field = false; + chnl->even_vcmp = false; + } + } else if (chnl->port.type == MCDE_PORTTYPE_DSI) { + if (dsi_use_clk_framework) { + clk_put(chnl->clk_dsi_lp); + clk_put(chnl->clk_dsi_hs); + } + } + + dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__); +} + +void mcde_chnl_stop_flow(struct mcde_chnl_state *chnl) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + mcde_lock(__func__, __LINE__); + if (mcde_is_enabled && chnl->enabled) + stop_channel(chnl); + mcde_unlock(__func__, __LINE__); + + dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__); +} + +void mcde_chnl_enable(struct mcde_chnl_state *chnl) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + mcde_lock(__func__, __LINE__); + _mcde_chnl_enable(chnl); + mcde_unlock(__func__, __LINE__); + + dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__); +} + +void mcde_chnl_disable(struct mcde_chnl_state *chnl) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + mcde_lock(__func__, __LINE__); + cancel_delayed_work(&hw_timeout_work); + /* The channel must be stopped before it is disabled */ + WARN_ON_ONCE(chnl->state == CHNLSTATE_RUNNING); + disable_mcde_hw(false, true); + chnl->enabled = false; + mcde_unlock(__func__, __LINE__); + + dev_vdbg(&mcde_dev->dev, "%s exit\n", __func__); +} + +/* MCDE overlays */ +struct mcde_ovly_state *mcde_ovly_get(struct mcde_chnl_state *chnl) +{ + struct mcde_ovly_state *ovly; + + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (!chnl->reserved) + return ERR_PTR(-EINVAL); + + if (!chnl->ovly0->inuse) + ovly = chnl->ovly0; + else if (chnl->ovly1 && !chnl->ovly1->inuse) + ovly = chnl->ovly1; + else + ovly = ERR_PTR(-EBUSY); + + if (!IS_ERR(ovly)) { + ovly->inuse = true; + ovly->paddr = 0; + ovly->stride = 0; + ovly->pix_fmt = MCDE_OVLYPIXFMT_RGB565; + ovly->src_x = 0; + ovly->src_y = 0; + ovly->dst_x = 0; + ovly->dst_y = 0; + ovly->dst_z = 0; + ovly->w = 0; + ovly->h = 0; + ovly->alpha_value = 0xFF; + ovly->alpha_source = MCDE_OVL1CONF2_BP_PER_PIXEL_ALPHA; + ovly->dirty = true; + mcde_ovly_apply(ovly); + } + + return ovly; +} + +void mcde_ovly_put(struct mcde_ovly_state *ovly) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (!ovly->inuse) + return; + if (ovly->regs.enabled) { + ovly->paddr = 0; + ovly->dirty = true; + mcde_ovly_apply(ovly);/* REVIEW: API call calling API call! */ + } + ovly->inuse = false; +} + +void mcde_ovly_set_source_buf(struct mcde_ovly_state *ovly, u32 paddr) +{ + if (!ovly->inuse) + return; + + ovly->dirty = paddr == 0 || ovly->paddr == 0; + ovly->dirty_buf = true; + + ovly->paddr = paddr; +} + +void mcde_ovly_set_source_info(struct mcde_ovly_state *ovly, + u32 stride, enum mcde_ovly_pix_fmt pix_fmt) +{ + if (!ovly->inuse) + return; + + ovly->stride = stride; + ovly->pix_fmt = pix_fmt; + ovly->dirty = true; +} + +void mcde_ovly_set_source_area(struct mcde_ovly_state *ovly, + u16 x, u16 y, u16 w, u16 h) +{ + if (!ovly->inuse) + return; + + ovly->src_x = x; + ovly->src_y = y; + ovly->w = w; + ovly->h = h; + ovly->dirty = true; +} + +void mcde_ovly_set_dest_pos(struct mcde_ovly_state *ovly, u16 x, u16 y, u8 z) +{ + if (!ovly->inuse) + return; + + ovly->dst_x = x; + ovly->dst_y = y; + ovly->dst_z = z; + ovly->dirty = true; +} + +void mcde_ovly_apply(struct mcde_ovly_state *ovly) +{ + if (!ovly->inuse) + return; + + mcde_lock(__func__, __LINE__); + + if (ovly->dirty || ovly->dirty_buf) { + ovly->regs.ch_id = ovly->chnl->id; + ovly->regs.enabled = ovly->paddr != 0; + ovly->regs.baseaddress0 = ovly->paddr; + ovly->regs.baseaddress1 = + ovly->regs.baseaddress0 + ovly->stride; + ovly->regs.dirty_buf = true; + ovly->dirty_buf = false; + } + if (!ovly->dirty) { + mcde_unlock(__func__, __LINE__); + return; + } + + switch (ovly->pix_fmt) {/* REVIEW: Extract to table */ + case MCDE_OVLYPIXFMT_RGB565: + ovly->regs.bits_per_pixel = 16; + ovly->regs.bpp = MCDE_EXTSRC0CONF_BPP_RGB565; + ovly->regs.bgr = false; + ovly->regs.bebo = false; + ovly->regs.opq = true; + break; + case MCDE_OVLYPIXFMT_RGBA5551: + ovly->regs.bits_per_pixel = 16; + ovly->regs.bpp = MCDE_EXTSRC0CONF_BPP_IRGB1555; + ovly->regs.bgr = false; + ovly->regs.bebo = false; + ovly->regs.opq = false; + break; + case MCDE_OVLYPIXFMT_RGBA4444: + ovly->regs.bits_per_pixel = 16; + ovly->regs.bpp = MCDE_EXTSRC0CONF_BPP_ARGB4444; + ovly->regs.bgr = false; + ovly->regs.bebo = false; + ovly->regs.opq = false; + break; + case MCDE_OVLYPIXFMT_RGB888: + ovly->regs.bits_per_pixel = 24; + ovly->regs.bpp = MCDE_EXTSRC0CONF_BPP_RGB888; + ovly->regs.bgr = false; + ovly->regs.bebo = false; + ovly->regs.opq = true; + break; + case MCDE_OVLYPIXFMT_RGBX8888: + ovly->regs.bits_per_pixel = 32; + ovly->regs.bpp = MCDE_EXTSRC0CONF_BPP_XRGB8888; + ovly->regs.bgr = false; + ovly->regs.bebo = true; + ovly->regs.opq = true; + break; + case MCDE_OVLYPIXFMT_RGBA8888: + ovly->regs.bits_per_pixel = 32; + ovly->regs.bpp = MCDE_EXTSRC0CONF_BPP_ARGB8888; + ovly->regs.bgr = false; + ovly->regs.bebo = false; + ovly->regs.opq = false; + break; + case MCDE_OVLYPIXFMT_YCbCr422: + ovly->regs.bits_per_pixel = 16; + ovly->regs.bpp = MCDE_EXTSRC0CONF_BPP_YCBCR422; + ovly->regs.bgr = false; + ovly->regs.bebo = false; + ovly->regs.opq = true; + break; + default: + break; + } + + ovly->regs.ppl = ovly->w; + ovly->regs.lpf = ovly->h; + ovly->regs.cropx = ovly->src_x; + ovly->regs.cropy = ovly->src_y; + ovly->regs.xpos = ovly->dst_x; + ovly->regs.ypos = ovly->dst_y; + ovly->regs.z = ovly->dst_z > 0; /* 0 or 1 */ + ovly->regs.col_conv = MCDE_OVL0CR_COLCCTRL_DISABLED; + ovly->regs.alpha_source = ovly->alpha_source; + ovly->regs.alpha_value = ovly->alpha_value; + + ovly->regs.dirty = true; + ovly->dirty = false; + + mcde_unlock(__func__, __LINE__); + + dev_vdbg(&mcde_dev->dev, "Overlay applied, idx=%d chnl=%d\n", + ovly->idx, ovly->chnl->id); +} + +static int init_clocks_and_power(struct platform_device *pdev) +{ + int ret = 0; + struct mcde_platform_data *pdata = pdev->dev.platform_data; + + if (pdata->regulator_mcde_epod_id) { + regulator_mcde_epod = regulator_get(&pdev->dev, + pdata->regulator_mcde_epod_id); + if (IS_ERR(regulator_mcde_epod)) { + ret = PTR_ERR(regulator_mcde_epod); + dev_warn(&pdev->dev, + "%s: Failed to get regulator '%s'\n", + __func__, pdata->regulator_mcde_epod_id); + regulator_mcde_epod = NULL; + return ret; + } + } else { + dev_warn(&pdev->dev, "%s: No mcde regulator id supplied\n", + __func__); + return -EINVAL; + } + + if (pdata->regulator_esram_epod_id) { + regulator_esram_epod = regulator_get(&pdev->dev, + pdata->regulator_esram_epod_id); + if (IS_ERR(regulator_esram_epod)) { + ret = PTR_ERR(regulator_esram_epod); + dev_warn(&pdev->dev, + "%s: Failed to get regulator '%s'\n", + __func__, pdata->regulator_esram_epod_id); + regulator_esram_epod = NULL; + goto regulator_esram_err; + } + } else { + dev_warn(&pdev->dev, "%s: No esram regulator id supplied\n", + __func__); + } + + if (pdata->regulator_vana_id) { + regulator_vana = regulator_get(&pdev->dev, + pdata->regulator_vana_id); + if (IS_ERR(regulator_vana)) { + ret = PTR_ERR(regulator_vana); + dev_warn(&pdev->dev, + "%s: Failed to get regulator '%s'\n", + __func__, pdata->regulator_vana_id); + regulator_vana = NULL; + goto regulator_vana_err; + } + } else { + dev_dbg(&pdev->dev, "%s: No vana regulator id supplied\n", + __func__); + } + + if (!dsi_use_clk_framework) { + clock_dsi = clk_get(&pdev->dev, pdata->clock_dsi_id); + if (IS_ERR(clock_dsi)) + dev_dbg(&pdev->dev, "%s: Failed to get clock '%s'\n", + __func__, pdata->clock_dsi_id); + + clock_dsi_lp = clk_get(&pdev->dev, pdata->clock_dsi_lp_id); + if (IS_ERR(clock_dsi_lp)) + dev_dbg(&pdev->dev, "%s: Failed to get clock '%s'\n", + __func__, pdata->clock_dsi_lp_id); + } + + clock_mcde = clk_get(&pdev->dev, CLK_MCDE); + if (IS_ERR(clock_mcde)) { + ret = PTR_ERR(clock_mcde); + dev_warn(&pdev->dev, "%s: Failed to get mcde_clk\n", __func__); + goto clk_mcde_err; + } + + return ret; + +clk_mcde_err: + if (!dsi_use_clk_framework) { + clk_put(clock_dsi_lp); + clk_put(clock_dsi); + } + + if (regulator_vana) + regulator_put(regulator_vana); +regulator_vana_err: + if (regulator_esram_epod) + regulator_put(regulator_esram_epod); +regulator_esram_err: + regulator_put(regulator_mcde_epod); + return ret; +} + +static void remove_clocks_and_power(struct platform_device *pdev) +{ + /* REVIEW: Release only if exist */ + /* REVIEW: Remove make sure MCDE is done */ + if (!dsi_use_clk_framework) { + clk_put(clock_dsi_lp); + clk_put(clock_dsi); + } + clk_put(clock_mcde); + if (regulator_vana) + regulator_put(regulator_vana); + regulator_put(regulator_mcde_epod); + regulator_put(regulator_esram_epod); +} + +static int probe_hw(struct platform_device *pdev) +{ + int i; + int ret; + u32 pid; + struct resource *res; + + dev_info(&mcde_dev->dev, "Probe HW\n"); + + /* Get MCDE HW version */ + regulator_enable(regulator_mcde_epod); + clk_enable(clock_mcde); + pid = mcde_rreg(MCDE_PID); + + dev_info(&mcde_dev->dev, "MCDE HW revision 0x%.8X\n", pid); + + clk_disable(clock_mcde); + regulator_disable(regulator_mcde_epod); + + switch (pid) { + case MCDE_VERSION_3_0_8: + num_dsilinks = 3; + num_channels = 4; + num_overlays = 6; + dsi_ifc_is_supported = true; + input_fifo_size = 128; + output_fifo_ab_size = 640; + output_fifo_c0c1_size = 160; + dsi_use_clk_framework = true; + dev_info(&mcde_dev->dev, "db8500 V2 HW\n"); + break; + case MCDE_VERSION_4_0_4: + num_dsilinks = 2; + num_channels = 2; + num_overlays = 3; + input_fifo_size = 80; + output_fifo_ab_size = 320; + dsi_ifc_is_supported = false; + dsi_use_clk_framework = false; + dev_info(&mcde_dev->dev, "db5500 V2 HW\n"); + break; + case MCDE_VERSION_4_1_3: + num_dsilinks = 3; + num_channels = 4; + num_overlays = 6; + dsi_ifc_is_supported = true; + input_fifo_size = 192; + output_fifo_ab_size = 640; + output_fifo_c0c1_size = 160; + dsi_use_clk_framework = false; + dev_info(&mcde_dev->dev, "db9540 V1 HW\n"); + break; + case MCDE_VERSION_3_0_5: + /* Intentional */ + case MCDE_VERSION_1_0_4: + /* Intentional */ + default: + dev_err(&mcde_dev->dev, "Unsupported HW version\n"); + ret = -ENOTSUPP; + goto unsupported_hw; + break; + } + + channels = kzalloc(num_channels * sizeof(struct mcde_chnl_state), + GFP_KERNEL); + if (!channels) { + ret = -ENOMEM; + goto failed_channels_alloc; + } + + overlays = kzalloc(num_overlays * sizeof(struct mcde_ovly_state), + GFP_KERNEL); + if (!overlays) { + ret = -ENOMEM; + goto failed_overlays_alloc; + } + + dsiio = kzalloc(num_dsilinks * sizeof(*dsiio), GFP_KERNEL); + if (!dsiio) { + ret = -ENOMEM; + goto failed_dsi_alloc; + } + + for (i = 0; i < num_dsilinks; i++) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 1+i); + if (!res) { + dev_dbg(&pdev->dev, "No DSI%d io defined\n", i); + ret = -EINVAL; + goto failed_get_dsi_io; + } + dsiio[i] = ioremap(res->start, res->end - res->start + 1); + if (!dsiio[i]) { + dev_dbg(&pdev->dev, "MCDE DSI%d iomap failed\n", i); + ret = -EINVAL; + goto failed_map_dsi_io; + } + dev_info(&pdev->dev, "MCDE DSI%d iomap: 0x%.8X->0x%.8X\n", + i, (u32)res->start, (u32)dsiio[i]); + } + + /* Init MCDE */ + for (i = 0; i < num_overlays; i++) + overlays[i].idx = i; + + channels[0].ovly0 = &overlays[0]; + channels[0].ovly1 = &overlays[1]; + channels[1].ovly0 = &overlays[2]; + + if (pid == MCDE_VERSION_3_0_8) { + channels[1].ovly1 = &overlays[3]; + channels[2].ovly0 = &overlays[4]; + channels[3].ovly0 = &overlays[5]; + } + + mcde_debugfs_create(&mcde_dev->dev); + for (i = 0; i < num_channels; i++) { + channels[i].id = i; + + channels[i].ovly0->chnl = &channels[i]; + if (channels[i].ovly1) + channels[i].ovly1->chnl = &channels[i]; + + init_waitqueue_head(&channels[i].state_waitq); + init_waitqueue_head(&channels[i].vcmp_waitq); + init_timer(&channels[i].dsi_te_timer); + channels[i].dsi_te_timer.function = + dsi_te_timer_function; + channels[i].dsi_te_timer.data = i; + + mcde_debugfs_channel_create(i, &channels[i]); + mcde_debugfs_overlay_create(i, 0); + if (channels[i].ovly1) + mcde_debugfs_overlay_create(i, 1); + } + (void) prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, "mcde", 100); + mcde_clk_rate = clk_get_rate(clock_mcde); + dev_info(&mcde_dev->dev, "MCDE_CLK is %d MHz\n", mcde_clk_rate); + prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "mcde"); + + return 0; + +failed_map_dsi_io: + for (i = 0; i < num_dsilinks; i++) { + if (dsiio[i]) + iounmap(dsiio[i]); + } +failed_get_dsi_io: + kfree(dsiio); + dsiio = NULL; +failed_dsi_alloc: + kfree(overlays); + overlays = NULL; +failed_overlays_alloc: + kfree(channels); + channels = NULL; +unsupported_hw: +failed_channels_alloc: + num_dsilinks = 0; + num_channels = 0; + num_overlays = 0; + return ret; +} + +static int __devinit mcde_probe(struct platform_device *pdev) +{ + int ret = 0; + struct resource *res; + struct mcde_platform_data *pdata = pdev->dev.platform_data; + + if (!pdata) { + dev_dbg(&pdev->dev, "No platform data\n"); + return -EINVAL; + } + + mcde_dev = pdev; + + /* Hook up irq */ + mcde_irq = platform_get_irq(pdev, 0); + if (mcde_irq <= 0) { + dev_dbg(&pdev->dev, "No irq defined\n"); + ret = -EINVAL; + goto failed_irq_get; + } + + /* Map I/O */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_dbg(&pdev->dev, "No MCDE io defined\n"); + ret = -EINVAL; + goto failed_get_mcde_io; + } + mcdeio = ioremap(res->start, res->end - res->start + 1); + if (!mcdeio) { + dev_dbg(&pdev->dev, "MCDE iomap failed\n"); + ret = -EINVAL; + goto failed_map_mcde_io; + } + dev_info(&pdev->dev, "MCDE iomap: 0x%.8X->0x%.8X\n", + (u32)res->start, (u32)mcdeio); + + ret = init_clocks_and_power(pdev); + if (ret < 0) { + dev_warn(&pdev->dev, "%s: init_clocks_and_power failed\n" + , __func__); + goto failed_init_clocks; + } + + INIT_DELAYED_WORK_DEFERRABLE(&hw_timeout_work, work_sleep_function); + + ret = probe_hw(pdev); + if (ret) + goto failed_probe_hw; + + ret = enable_mcde_hw(); + if (ret) + goto failed_mcde_enable; + + return 0; + +failed_mcde_enable: +failed_probe_hw: + remove_clocks_and_power(pdev); +failed_init_clocks: + iounmap(mcdeio); +failed_map_mcde_io: +failed_get_mcde_io: +failed_irq_get: + return ret; +} + +static int __devexit mcde_remove(struct platform_device *pdev) +{ + struct mcde_chnl_state *chnl = &channels[0]; + + for (; chnl < &channels[num_channels]; chnl++) { + if (del_timer(&chnl->dsi_te_timer)) + dev_vdbg(&mcde_dev->dev, + "%s dsi timer could not be stopped\n" + , __func__); + } + + remove_clocks_and_power(pdev); + return 0; +} + +#if !defined(CONFIG_HAS_EARLYSUSPEND) && defined(CONFIG_PM) +static int mcde_resume(struct platform_device *pdev) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + mcde_lock(__func__, __LINE__); + + if (enable_mcde_hw()) { + mcde_unlock(__func__, __LINE__); + return -EINVAL; + } + + mcde_unlock(__func__, __LINE__); + + return 0; +} + +static int mcde_suspend(struct platform_device *pdev, pm_message_t state) +{ + int ret; + + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + mcde_lock(__func__, __LINE__); + + cancel_delayed_work(&hw_timeout_work); + + if (!mcde_is_enabled) { + mcde_unlock(__func__, __LINE__); + return 0; + } + disable_mcde_hw(true, true); + + mcde_unlock(__func__, __LINE__); + + return ret; +} +#endif + +static struct platform_driver mcde_driver = { + .probe = mcde_probe, + .remove = mcde_remove, +#if !defined(CONFIG_HAS_EARLYSUSPEND) && defined(CONFIG_PM) + .suspend = mcde_suspend, + .resume = mcde_resume, +#else + .suspend = NULL, + .resume = NULL, +#endif + .driver = { + .name = "mcde", + }, +}; + +int __init mcde_init(void) +{ + mutex_init(&mcde_hw_lock); + return platform_driver_register(&mcde_driver); +} + +void mcde_exit(void) +{ + /* REVIEW: shutdown MCDE? */ + platform_driver_unregister(&mcde_driver); +} diff --git a/drivers/video/mcde/mcde_mod.c b/drivers/video/mcde/mcde_mod.c new file mode 100644 index 00000000000..60df0d4965f --- /dev/null +++ b/drivers/video/mcde/mcde_mod.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * + * ST-Ericsson MCDE driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ +#include <linux/init.h> +#include <linux/module.h> + +#include <video/mcde.h> +#include <video/mcde_fb.h> +#include <video/mcde_dss.h> +#include <video/mcde_display.h> + +/* Module init */ + +static int __init mcde_subsystem_init(void) +{ + int ret; + pr_info("MCDE subsystem init begin\n"); + + /* MCDE module init sequence */ + ret = mcde_init(); + if (ret) + goto mcde_failed; + ret = mcde_display_init(); + if (ret) + goto mcde_display_failed; + ret = mcde_dss_init(); + if (ret) + goto mcde_dss_failed; + ret = mcde_fb_init(); + if (ret) + goto mcde_fb_failed; + pr_info("MCDE subsystem init done\n"); + + goto done; +mcde_fb_failed: + mcde_dss_exit(); +mcde_dss_failed: + mcde_display_exit(); +mcde_display_failed: + mcde_exit(); +mcde_failed: +done: + return ret; +} +#ifdef MODULE +module_init(mcde_subsystem_init); +#else +fs_initcall(mcde_subsystem_init); +#endif + +static void __exit mcde_module_exit(void) +{ + mcde_exit(); + mcde_display_exit(); + mcde_dss_exit(); +} +module_exit(mcde_module_exit); + +MODULE_AUTHOR("Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ST-Ericsson MCDE driver"); + diff --git a/drivers/video/mcde/mcde_regs.h b/drivers/video/mcde/mcde_regs.h new file mode 100644 index 00000000000..0eece3faea2 --- /dev/null +++ b/drivers/video/mcde/mcde_regs.h @@ -0,0 +1,5096 @@ + +#define MCDE_VAL2REG(__reg, __fld, __val) \ + (((__val) << __reg##_##__fld##_SHIFT) & __reg##_##__fld##_MASK) +#define MCDE_REG2VAL(__reg, __fld, __val) \ + (((__val) & __reg##_##__fld##_MASK) >> __reg##_##__fld##_SHIFT) + +#define MCDE_CR 0x00000000 +#define MCDE_CR_IFIFOCTRLEN_SHIFT 15 +#define MCDE_CR_IFIFOCTRLEN_MASK 0x00008000 +#define MCDE_CR_IFIFOCTRLEN(__x) \ + MCDE_VAL2REG(MCDE_CR, IFIFOCTRLEN, __x) +#define MCDE_CR_AUTOCLKG_EN_SHIFT 30 +#define MCDE_CR_AUTOCLKG_EN_MASK 0x40000000 +#define MCDE_CR_AUTOCLKG_EN(__x) \ + MCDE_VAL2REG(MCDE_CR, AUTOCLKG_EN, __x) +#define MCDE_CR_MCDEEN_SHIFT 31 +#define MCDE_CR_MCDEEN_MASK 0x80000000 +#define MCDE_CR_MCDEEN(__x) \ + MCDE_VAL2REG(MCDE_CR, MCDEEN, __x) +#define MCDE_CONF0 0x00000004 +#define MCDE_CONF0_SYNCMUX0_SHIFT 0 +#define MCDE_CONF0_SYNCMUX0_MASK 0x00000001 +#define MCDE_CONF0_SYNCMUX0(__x) \ + MCDE_VAL2REG(MCDE_CONF0, SYNCMUX0, __x) +#define MCDE_CONF0_SYNCMUX1_SHIFT 1 +#define MCDE_CONF0_SYNCMUX1_MASK 0x00000002 +#define MCDE_CONF0_SYNCMUX1(__x) \ + MCDE_VAL2REG(MCDE_CONF0, SYNCMUX1, __x) +#define MCDE_CONF0_SYNCMUX2_SHIFT 2 +#define MCDE_CONF0_SYNCMUX2_MASK 0x00000004 +#define MCDE_CONF0_SYNCMUX2(__x) \ + MCDE_VAL2REG(MCDE_CONF0, SYNCMUX2, __x) +#define MCDE_CONF0_SYNCMUX3_SHIFT 3 +#define MCDE_CONF0_SYNCMUX3_MASK 0x00000008 +#define MCDE_CONF0_SYNCMUX3(__x) \ + MCDE_VAL2REG(MCDE_CONF0, SYNCMUX3, __x) +#define MCDE_CONF0_SYNCMUX4_SHIFT 4 +#define MCDE_CONF0_SYNCMUX4_MASK 0x00000010 +#define MCDE_CONF0_SYNCMUX4(__x) \ + MCDE_VAL2REG(MCDE_CONF0, SYNCMUX4, __x) +#define MCDE_CONF0_SYNCMUX5_SHIFT 5 +#define MCDE_CONF0_SYNCMUX5_MASK 0x00000020 +#define MCDE_CONF0_SYNCMUX5(__x) \ + MCDE_VAL2REG(MCDE_CONF0, SYNCMUX5, __x) +#define MCDE_CONF0_SYNCMUX6_SHIFT 6 +#define MCDE_CONF0_SYNCMUX6_MASK 0x00000040 +#define MCDE_CONF0_SYNCMUX6(__x) \ + MCDE_VAL2REG(MCDE_CONF0, SYNCMUX6, __x) +#define MCDE_CONF0_SYNCMUX7_SHIFT 7 +#define MCDE_CONF0_SYNCMUX7_MASK 0x00000080 +#define MCDE_CONF0_SYNCMUX7(__x) \ + MCDE_VAL2REG(MCDE_CONF0, SYNCMUX7, __x) +#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_SHIFT 12 +#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL_MASK 0x00007000 +#define MCDE_CONF0_IFIFOCTRLWTRMRKLVL(__x) \ + MCDE_VAL2REG(MCDE_CONF0, IFIFOCTRLWTRMRKLVL, __x) +#define MCDE_CONF0_OUTMUX0_SHIFT 16 +#define MCDE_CONF0_OUTMUX0_MASK 0x00070000 +#define MCDE_CONF0_OUTMUX0(__x) \ + MCDE_VAL2REG(MCDE_CONF0, OUTMUX0, __x) +#define MCDE_CONF0_OUTMUX1_SHIFT 19 +#define MCDE_CONF0_OUTMUX1_MASK 0x00380000 +#define MCDE_CONF0_OUTMUX1(__x) \ + MCDE_VAL2REG(MCDE_CONF0, OUTMUX1, __x) +#define MCDE_CONF0_OUTMUX2_SHIFT 22 +#define MCDE_CONF0_OUTMUX2_MASK 0x01C00000 +#define MCDE_CONF0_OUTMUX2(__x) \ + MCDE_VAL2REG(MCDE_CONF0, OUTMUX2, __x) +#define MCDE_CONF0_OUTMUX3_SHIFT 25 +#define MCDE_CONF0_OUTMUX3_MASK 0x0E000000 +#define MCDE_CONF0_OUTMUX3(__x) \ + MCDE_VAL2REG(MCDE_CONF0, OUTMUX3, __x) +#define MCDE_CONF0_OUTMUX4_SHIFT 28 +#define MCDE_CONF0_OUTMUX4_MASK 0x70000000 +#define MCDE_CONF0_OUTMUX4(__x) \ + MCDE_VAL2REG(MCDE_CONF0, OUTMUX4, __x) +#define MCDE_SSP 0x00000008 +#define MCDE_SSP_SSPDATA_SHIFT 0 +#define MCDE_SSP_SSPDATA_MASK 0x000000FF +#define MCDE_SSP_SSPDATA(__x) \ + MCDE_VAL2REG(MCDE_SSP, SSPDATA, __x) +#define MCDE_SSP_SSPCMD_SHIFT 8 +#define MCDE_SSP_SSPCMD_MASK 0x00000100 +#define MCDE_SSP_SSPCMD_DATA 0 +#define MCDE_SSP_SSPCMD_COMMAND 1 +#define MCDE_SSP_SSPCMD_ENUM(__x) \ + MCDE_VAL2REG(MCDE_SSP, SSPCMD, MCDE_SSP_SSPCMD_##__x) +#define MCDE_SSP_SSPCMD(__x) \ + MCDE_VAL2REG(MCDE_SSP, SSPCMD, __x) +#define MCDE_SSP_SSPEN_SHIFT 16 +#define MCDE_SSP_SSPEN_MASK 0x00010000 +#define MCDE_SSP_SSPEN(__x) \ + MCDE_VAL2REG(MCDE_SSP, SSPEN, __x) +#define MCDE_AIS 0x00000100 +#define MCDE_AIS_MCDEPPI_SHIFT 0 +#define MCDE_AIS_MCDEPPI_MASK 0x00000001 +#define MCDE_AIS_MCDEPPI(__x) \ + MCDE_VAL2REG(MCDE_AIS, MCDEPPI, __x) +#define MCDE_AIS_MCDEOVLI_SHIFT 1 +#define MCDE_AIS_MCDEOVLI_MASK 0x00000002 +#define MCDE_AIS_MCDEOVLI(__x) \ + MCDE_VAL2REG(MCDE_AIS, MCDEOVLI, __x) +#define MCDE_AIS_MCDECHNLI_SHIFT 2 +#define MCDE_AIS_MCDECHNLI_MASK 0x00000004 +#define MCDE_AIS_MCDECHNLI(__x) \ + MCDE_VAL2REG(MCDE_AIS, MCDECHNLI, __x) +#define MCDE_AIS_MCDEERRI_SHIFT 3 +#define MCDE_AIS_MCDEERRI_MASK 0x00000008 +#define MCDE_AIS_MCDEERRI(__x) \ + MCDE_VAL2REG(MCDE_AIS, MCDEERRI, __x) +#define MCDE_AIS_DSI0AI_SHIFT 4 +#define MCDE_AIS_DSI0AI_MASK 0x00000010 +#define MCDE_AIS_DSI0AI(__x) \ + MCDE_VAL2REG(MCDE_AIS, DSI0AI, __x) +#define MCDE_AIS_DSI1AI_SHIFT 5 +#define MCDE_AIS_DSI1AI_MASK 0x00000020 +#define MCDE_AIS_DSI1AI(__x) \ + MCDE_VAL2REG(MCDE_AIS, DSI1AI, __x) +#define MCDE_AIS_DSI2AI_SHIFT 6 +#define MCDE_AIS_DSI2AI_MASK 0x00000040 +#define MCDE_AIS_DSI2AI(__x) \ + MCDE_VAL2REG(MCDE_AIS, DSI2AI, __x) +#define MCDE_IMSCPP 0x00000104 +#define MCDE_IMSCPP_VCMPAIM_SHIFT 0 +#define MCDE_IMSCPP_VCMPAIM_MASK 0x00000001 +#define MCDE_IMSCPP_VCMPAIM(__x) \ + MCDE_VAL2REG(MCDE_IMSCPP, VCMPAIM, __x) +#define MCDE_IMSCPP_VCMPBIM_SHIFT 1 +#define MCDE_IMSCPP_VCMPBIM_MASK 0x00000002 +#define MCDE_IMSCPP_VCMPBIM(__x) \ + MCDE_VAL2REG(MCDE_IMSCPP, VCMPBIM, __x) +#define MCDE_IMSCPP_VSCC0IM_SHIFT 2 +#define MCDE_IMSCPP_VSCC0IM_MASK 0x00000004 +#define MCDE_IMSCPP_VSCC0IM(__x) \ + MCDE_VAL2REG(MCDE_IMSCPP, VSCC0IM, __x) +#define MCDE_IMSCPP_VSCC1IM_SHIFT 3 +#define MCDE_IMSCPP_VSCC1IM_MASK 0x00000008 +#define MCDE_IMSCPP_VSCC1IM(__x) \ + MCDE_VAL2REG(MCDE_IMSCPP, VSCC1IM, __x) +#define MCDE_IMSCPP_VCMPC0IM_SHIFT 4 +#define MCDE_IMSCPP_VCMPC0IM_MASK 0x00000010 +#define MCDE_IMSCPP_VCMPC0IM(__x) \ + MCDE_VAL2REG(MCDE_IMSCPP, VCMPC0IM, __x) +#define MCDE_IMSCPP_VCMPC1IM_SHIFT 5 +#define MCDE_IMSCPP_VCMPC1IM_MASK 0x00000020 +#define MCDE_IMSCPP_VCMPC1IM(__x) \ + MCDE_VAL2REG(MCDE_IMSCPP, VCMPC1IM, __x) +#define MCDE_IMSCPP_ROTFDIM_B_SHIFT 6 +#define MCDE_IMSCPP_ROTFDIM_B_MASK 0x00000040 +#define MCDE_IMSCPP_ROTFDIM_B(__x) \ + MCDE_VAL2REG(MCDE_IMSCPP, ROTFDIM_B, __x) +#define MCDE_IMSCPP_ROTFDIM_A_SHIFT 7 +#define MCDE_IMSCPP_ROTFDIM_A_MASK 0x00000080 +#define MCDE_IMSCPP_ROTFDIM_A(__x) \ + MCDE_VAL2REG(MCDE_IMSCPP, ROTFDIM_A, __x) +#define MCDE_IMSCOVL 0x00000108 +#define MCDE_IMSCOVL_OVLRDIM_SHIFT 0 +#define MCDE_IMSCOVL_OVLRDIM_MASK 0x0000FFFF +#define MCDE_IMSCOVL_OVLRDIM(__x) \ + MCDE_VAL2REG(MCDE_IMSCOVL, OVLRDIM, __x) +#define MCDE_IMSCOVL_OVLFDIM_SHIFT 16 +#define MCDE_IMSCOVL_OVLFDIM_MASK 0xFFFF0000 +#define MCDE_IMSCOVL_OVLFDIM(__x) \ + MCDE_VAL2REG(MCDE_IMSCOVL, OVLFDIM, __x) +#define MCDE_IMSCCHNL 0x0000010C +#define MCDE_IMSCCHNL_CHNLRDIM_SHIFT 0 +#define MCDE_IMSCCHNL_CHNLRDIM_MASK 0x0000FFFF +#define MCDE_IMSCCHNL_CHNLRDIM(__x) \ + MCDE_VAL2REG(MCDE_IMSCCHNL, CHNLRDIM, __x) +#define MCDE_IMSCCHNL_CHNLAIM_SHIFT 16 +#define MCDE_IMSCCHNL_CHNLAIM_MASK 0xFFFF0000 +#define MCDE_IMSCCHNL_CHNLAIM(__x) \ + MCDE_VAL2REG(MCDE_IMSCCHNL, CHNLAIM, __x) +#define MCDE_IMSCERR 0x00000110 +#define MCDE_IMSCERR_FUAIM_SHIFT 0 +#define MCDE_IMSCERR_FUAIM_MASK 0x00000001 +#define MCDE_IMSCERR_FUAIM(__x) \ + MCDE_VAL2REG(MCDE_IMSCERR, FUAIM, __x) +#define MCDE_IMSCERR_FUBIM_SHIFT 1 +#define MCDE_IMSCERR_FUBIM_MASK 0x00000002 +#define MCDE_IMSCERR_FUBIM(__x) \ + MCDE_VAL2REG(MCDE_IMSCERR, FUBIM, __x) +#define MCDE_IMSCERR_SCHBLCKDIM_SHIFT 2 +#define MCDE_IMSCERR_SCHBLCKDIM_MASK 0x00000004 +#define MCDE_IMSCERR_SCHBLCKDIM(__x) \ + MCDE_VAL2REG(MCDE_IMSCERR, SCHBLCKDIM, __x) +#define MCDE_IMSCERR_ROTAFEIM_WRITE_SHIFT 3 +#define MCDE_IMSCERR_ROTAFEIM_WRITE_MASK 0x00000008 +#define MCDE_IMSCERR_ROTAFEIM_WRITE(__x) \ + MCDE_VAL2REG(MCDE_IMSCERR, ROTAFEIM_WRITE, __x) +#define MCDE_IMSCERR_ROTAFEIM_READ_SHIFT 4 +#define MCDE_IMSCERR_ROTAFEIM_READ_MASK 0x00000010 +#define MCDE_IMSCERR_ROTAFEIM_READ(__x) \ + MCDE_VAL2REG(MCDE_IMSCERR, ROTAFEIM_READ, __x) +#define MCDE_IMSCERR_ROTBFEIM_WRITE_SHIFT 5 +#define MCDE_IMSCERR_ROTBFEIM_WRITE_MASK 0x00000020 +#define MCDE_IMSCERR_ROTBFEIM_WRITE(__x) \ + MCDE_VAL2REG(MCDE_IMSCERR, ROTBFEIM_WRITE, __x) +#define MCDE_IMSCERR_ROTBFEIM_READ_SHIFT 6 +#define MCDE_IMSCERR_ROTBFEIM_READ_MASK 0x00000040 +#define MCDE_IMSCERR_ROTBFEIM_READ(__x) \ + MCDE_VAL2REG(MCDE_IMSCERR, ROTBFEIM_READ, __x) +#define MCDE_IMSCERR_FUC0IM_SHIFT 7 +#define MCDE_IMSCERR_FUC0IM_MASK 0x00000080 +#define MCDE_IMSCERR_FUC0IM(__x) \ + MCDE_VAL2REG(MCDE_IMSCERR, FUC0IM, __x) +#define MCDE_IMSCERR_FUC1IM_SHIFT 8 +#define MCDE_IMSCERR_FUC1IM_MASK 0x00000100 +#define MCDE_IMSCERR_FUC1IM(__x) \ + MCDE_VAL2REG(MCDE_IMSCERR, FUC1IM, __x) +#define MCDE_IMSCERR_OVLFERRIM_SHIFT 16 +#define MCDE_IMSCERR_OVLFERRIM_MASK 0xFFFF0000 +#define MCDE_IMSCERR_OVLFERRIM(__x) \ + MCDE_VAL2REG(MCDE_IMSCERR, OVLFERRIM, __x) +#define MCDE_RISPP 0x00000114 +#define MCDE_RISPP_VCMPARIS_SHIFT 0 +#define MCDE_RISPP_VCMPARIS_MASK 0x00000001 +#define MCDE_RISPP_VCMPARIS(__x) \ + MCDE_VAL2REG(MCDE_RISPP, VCMPARIS, __x) +#define MCDE_RISPP_VCMPBRIS_SHIFT 1 +#define MCDE_RISPP_VCMPBRIS_MASK 0x00000002 +#define MCDE_RISPP_VCMPBRIS(__x) \ + MCDE_VAL2REG(MCDE_RISPP, VCMPBRIS, __x) +#define MCDE_RISPP_VSCC0RIS_SHIFT 2 +#define MCDE_RISPP_VSCC0RIS_MASK 0x00000004 +#define MCDE_RISPP_VSCC0RIS(__x) \ + MCDE_VAL2REG(MCDE_RISPP, VSCC0RIS, __x) +#define MCDE_RISPP_VSCC1RIS_SHIFT 3 +#define MCDE_RISPP_VSCC1RIS_MASK 0x00000008 +#define MCDE_RISPP_VSCC1RIS(__x) \ + MCDE_VAL2REG(MCDE_RISPP, VSCC1RIS, __x) +#define MCDE_RISPP_VCMPC0RIS_SHIFT 4 +#define MCDE_RISPP_VCMPC0RIS_MASK 0x00000010 +#define MCDE_RISPP_VCMPC0RIS(__x) \ + MCDE_VAL2REG(MCDE_RISPP, VCMPC0RIS, __x) +#define MCDE_RISPP_VCMPC1RIS_SHIFT 5 +#define MCDE_RISPP_VCMPC1RIS_MASK 0x00000020 +#define MCDE_RISPP_VCMPC1RIS(__x) \ + MCDE_VAL2REG(MCDE_RISPP, VCMPC1RIS, __x) +#define MCDE_RISPP_ROTFDRIS_B_SHIFT 6 +#define MCDE_RISPP_ROTFDRIS_B_MASK 0x00000040 +#define MCDE_RISPP_ROTFDRIS_B(__x) \ + MCDE_VAL2REG(MCDE_RISPP, ROTFDRIS_B, __x) +#define MCDE_RISPP_ROTFDRIS_A_SHIFT 7 +#define MCDE_RISPP_ROTFDRIS_A_MASK 0x00000080 +#define MCDE_RISPP_ROTFDRIS_A(__x) \ + MCDE_VAL2REG(MCDE_RISPP, ROTFDRIS_A, __x) +#define MCDE_RISOVL 0x00000118 +#define MCDE_RISOVL_OVLRDRIS_SHIFT 0 +#define MCDE_RISOVL_OVLRDRIS_MASK 0x0000FFFF +#define MCDE_RISOVL_OVLRDRIS(__x) \ + MCDE_VAL2REG(MCDE_RISOVL, OVLRDRIS, __x) +#define MCDE_RISOVL_OVLFDRIS_SHIFT 16 +#define MCDE_RISOVL_OVLFDRIS_MASK 0xFFFF0000 +#define MCDE_RISOVL_OVLFDRIS(__x) \ + MCDE_VAL2REG(MCDE_RISOVL, OVLFDRIS, __x) +#define MCDE_RISCHNL 0x0000011C +#define MCDE_RISCHNL_CHNLRDRIS_SHIFT 0 +#define MCDE_RISCHNL_CHNLRDRIS_MASK 0x0000FFFF +#define MCDE_RISCHNL_CHNLRDRIS(__x) \ + MCDE_VAL2REG(MCDE_RISCHNL, CHNLRDRIS, __x) +#define MCDE_RISCHNL_CHNLARIS_SHIFT 16 +#define MCDE_RISCHNL_CHNLARIS_MASK 0xFFFF0000 +#define MCDE_RISCHNL_CHNLARIS(__x) \ + MCDE_VAL2REG(MCDE_RISCHNL, CHNLARIS, __x) +#define MCDE_RISERR 0x00000120 +#define MCDE_RISERR_FUARIS_SHIFT 0 +#define MCDE_RISERR_FUARIS_MASK 0x00000001 +#define MCDE_RISERR_FUARIS(__x) \ + MCDE_VAL2REG(MCDE_RISERR, FUARIS, __x) +#define MCDE_RISERR_FUBRIS_SHIFT 1 +#define MCDE_RISERR_FUBRIS_MASK 0x00000002 +#define MCDE_RISERR_FUBRIS(__x) \ + MCDE_VAL2REG(MCDE_RISERR, FUBRIS, __x) +#define MCDE_RISERR_SCHBLCKDRIS_SHIFT 2 +#define MCDE_RISERR_SCHBLCKDRIS_MASK 0x00000004 +#define MCDE_RISERR_SCHBLCKDRIS(__x) \ + MCDE_VAL2REG(MCDE_RISERR, SCHBLCKDRIS, __x) +#define MCDE_RISERR_ROTAFERIS_WRITE_SHIFT 3 +#define MCDE_RISERR_ROTAFERIS_WRITE_MASK 0x00000008 +#define MCDE_RISERR_ROTAFERIS_WRITE(__x) \ + MCDE_VAL2REG(MCDE_RISERR, ROTAFERIS_WRITE, __x) +#define MCDE_RISERR_ROTAFERIS_READ_SHIFT 4 +#define MCDE_RISERR_ROTAFERIS_READ_MASK 0x00000010 +#define MCDE_RISERR_ROTAFERIS_READ(__x) \ + MCDE_VAL2REG(MCDE_RISERR, ROTAFERIS_READ, __x) +#define MCDE_RISERR_ROTBFERIS_WRITE_SHIFT 5 +#define MCDE_RISERR_ROTBFERIS_WRITE_MASK 0x00000020 +#define MCDE_RISERR_ROTBFERIS_WRITE(__x) \ + MCDE_VAL2REG(MCDE_RISERR, ROTBFERIS_WRITE, __x) +#define MCDE_RISERR_ROTBFERIS_READ_SHIFT 6 +#define MCDE_RISERR_ROTBFERIS_READ_MASK 0x00000040 +#define MCDE_RISERR_ROTBFERIS_READ(__x) \ + MCDE_VAL2REG(MCDE_RISERR, ROTBFERIS_READ, __x) +#define MCDE_RISERR_FUC0RIS_SHIFT 7 +#define MCDE_RISERR_FUC0RIS_MASK 0x00000080 +#define MCDE_RISERR_FUC0RIS(__x) \ + MCDE_VAL2REG(MCDE_RISERR, FUC0RIS, __x) +#define MCDE_RISERR_FUC1RIS_SHIFT 8 +#define MCDE_RISERR_FUC1RIS_MASK 0x00000100 +#define MCDE_RISERR_FUC1RIS(__x) \ + MCDE_VAL2REG(MCDE_RISERR, FUC1RIS, __x) +#define MCDE_RISERR_OVLFERRRIS_SHIFT 16 +#define MCDE_RISERR_OVLFERRRIS_MASK 0xFFFF0000 +#define MCDE_RISERR_OVLFERRRIS(__x) \ + MCDE_VAL2REG(MCDE_RISERR, OVLFERRRIS, __x) +#define MCDE_MISPP 0x00000124 +#define MCDE_MISPP_VCMPAMIS_SHIFT 0 +#define MCDE_MISPP_VCMPAMIS_MASK 0x00000001 +#define MCDE_MISPP_VCMPAMIS(__x) \ + MCDE_VAL2REG(MCDE_MISPP, VCMPAMIS, __x) +#define MCDE_MISPP_VCMPBMIS_SHIFT 1 +#define MCDE_MISPP_VCMPBMIS_MASK 0x00000002 +#define MCDE_MISPP_VCMPBMIS(__x) \ + MCDE_VAL2REG(MCDE_MISPP, VCMPBMIS, __x) +#define MCDE_MISPP_VSCC0MIS_SHIFT 2 +#define MCDE_MISPP_VSCC0MIS_MASK 0x00000004 +#define MCDE_MISPP_VSCC0MIS(__x) \ + MCDE_VAL2REG(MCDE_MISPP, VSCC0MIS, __x) +#define MCDE_MISPP_VSCC1MIS_SHIFT 3 +#define MCDE_MISPP_VSCC1MIS_MASK 0x00000008 +#define MCDE_MISPP_VSCC1MIS(__x) \ + MCDE_VAL2REG(MCDE_MISPP, VSCC1MIS, __x) +#define MCDE_MISPP_VCMPC0MIS_SHIFT 4 +#define MCDE_MISPP_VCMPC0MIS_MASK 0x00000010 +#define MCDE_MISPP_VCMPC0MIS(__x) \ + MCDE_VAL2REG(MCDE_MISPP, VCMPC0MIS, __x) +#define MCDE_MISPP_VCMPC1MIS_SHIFT 5 +#define MCDE_MISPP_VCMPC1MIS_MASK 0x00000020 +#define MCDE_MISPP_VCMPC1MIS(__x) \ + MCDE_VAL2REG(MCDE_MISPP, VCMPC1MIS, __x) +#define MCDE_MISPP_ROTFDMIS_A_SHIFT 6 +#define MCDE_MISPP_ROTFDMIS_A_MASK 0x00000040 +#define MCDE_MISPP_ROTFDMIS_A(__x) \ + MCDE_VAL2REG(MCDE_MISPP, ROTFDMIS_A, __x) +#define MCDE_MISPP_ROTFDMIS_B_SHIFT 7 +#define MCDE_MISPP_ROTFDMIS_B_MASK 0x00000080 +#define MCDE_MISPP_ROTFDMIS_B(__x) \ + MCDE_VAL2REG(MCDE_MISPP, ROTFDMIS_B, __x) +#define MCDE_MISOVL 0x00000128 +#define MCDE_MISOVL_OVLRDMIS_SHIFT 0 +#define MCDE_MISOVL_OVLRDMIS_MASK 0x0000FFFF +#define MCDE_MISOVL_OVLRDMIS(__x) \ + MCDE_VAL2REG(MCDE_MISOVL, OVLRDMIS, __x) +#define MCDE_MISOVL_OVLFDMIS_SHIFT 16 +#define MCDE_MISOVL_OVLFDMIS_MASK 0xFFFF0000 +#define MCDE_MISOVL_OVLFDMIS(__x) \ + MCDE_VAL2REG(MCDE_MISOVL, OVLFDMIS, __x) +#define MCDE_MISCHNL 0x0000012C +#define MCDE_MISCHNL_CHNLRDMIS_SHIFT 0 +#define MCDE_MISCHNL_CHNLRDMIS_MASK 0x0000FFFF +#define MCDE_MISCHNL_CHNLRDMIS(__x) \ + MCDE_VAL2REG(MCDE_MISCHNL, CHNLRDMIS, __x) +#define MCDE_MISCHNL_CHNLAMIS_SHIFT 16 +#define MCDE_MISCHNL_CHNLAMIS_MASK 0xFFFF0000 +#define MCDE_MISCHNL_CHNLAMIS(__x) \ + MCDE_VAL2REG(MCDE_MISCHNL, CHNLAMIS, __x) +#define MCDE_MISERR 0x00000130 +#define MCDE_MISERR_FUAMIS_SHIFT 0 +#define MCDE_MISERR_FUAMIS_MASK 0x00000001 +#define MCDE_MISERR_FUAMIS(__x) \ + MCDE_VAL2REG(MCDE_MISERR, FUAMIS, __x) +#define MCDE_MISERR_FUBMIS_SHIFT 1 +#define MCDE_MISERR_FUBMIS_MASK 0x00000002 +#define MCDE_MISERR_FUBMIS(__x) \ + MCDE_VAL2REG(MCDE_MISERR, FUBMIS, __x) +#define MCDE_MISERR_SCHBLCKDMIS_SHIFT 2 +#define MCDE_MISERR_SCHBLCKDMIS_MASK 0x00000004 +#define MCDE_MISERR_SCHBLCKDMIS(__x) \ + MCDE_VAL2REG(MCDE_MISERR, SCHBLCKDMIS, __x) +#define MCDE_MISERR_ROTAFEMIS_WRITE_SHIFT 3 +#define MCDE_MISERR_ROTAFEMIS_WRITE_MASK 0x00000008 +#define MCDE_MISERR_ROTAFEMIS_WRITE(__x) \ + MCDE_VAL2REG(MCDE_MISERR, ROTAFEMIS_WRITE, __x) +#define MCDE_MISERR_ROTAFEMIS_READ_SHIFT 4 +#define MCDE_MISERR_ROTAFEMIS_READ_MASK 0x00000010 +#define MCDE_MISERR_ROTAFEMIS_READ(__x) \ + MCDE_VAL2REG(MCDE_MISERR, ROTAFEMIS_READ, __x) +#define MCDE_MISERR_ROTBFEMIS_WRITE_SHIFT 5 +#define MCDE_MISERR_ROTBFEMIS_WRITE_MASK 0x00000020 +#define MCDE_MISERR_ROTBFEMIS_WRITE(__x) \ + MCDE_VAL2REG(MCDE_MISERR, ROTBFEMIS_WRITE, __x) +#define MCDE_MISERR_ROTBFEMIS_READ_SHIFT 6 +#define MCDE_MISERR_ROTBFEMIS_READ_MASK 0x00000040 +#define MCDE_MISERR_ROTBFEMIS_READ(__x) \ + MCDE_VAL2REG(MCDE_MISERR, ROTBFEMIS_READ, __x) +#define MCDE_MISERR_FUC0MIS_SHIFT 7 +#define MCDE_MISERR_FUC0MIS_MASK 0x00000080 +#define MCDE_MISERR_FUC0MIS(__x) \ + MCDE_VAL2REG(MCDE_MISERR, FUC0MIS, __x) +#define MCDE_MISERR_FUC1MIS_SHIFT 8 +#define MCDE_MISERR_FUC1MIS_MASK 0x00000100 +#define MCDE_MISERR_FUC1MIS(__x) \ + MCDE_VAL2REG(MCDE_MISERR, FUC1MIS, __x) +#define MCDE_MISERR_OVLFERMIS_SHIFT 16 +#define MCDE_MISERR_OVLFERMIS_MASK 0xFFFF0000 +#define MCDE_MISERR_OVLFERMIS(__x) \ + MCDE_VAL2REG(MCDE_MISERR, OVLFERMIS, __x) +#define MCDE_SISPP 0x00000134 +#define MCDE_SISPP_VCMPASIS_SHIFT 0 +#define MCDE_SISPP_VCMPASIS_MASK 0x00000001 +#define MCDE_SISPP_VCMPASIS(__x) \ + MCDE_VAL2REG(MCDE_SISPP, VCMPASIS, __x) +#define MCDE_SISPP_VCMPBSIS_SHIFT 1 +#define MCDE_SISPP_VCMPBSIS_MASK 0x00000002 +#define MCDE_SISPP_VCMPBSIS(__x) \ + MCDE_VAL2REG(MCDE_SISPP, VCMPBSIS, __x) +#define MCDE_SISPP_VSCC0SIS_SHIFT 2 +#define MCDE_SISPP_VSCC0SIS_MASK 0x00000004 +#define MCDE_SISPP_VSCC0SIS(__x) \ + MCDE_VAL2REG(MCDE_SISPP, VSCC0SIS, __x) +#define MCDE_SISPP_VSCC1SIS_SHIFT 3 +#define MCDE_SISPP_VSCC1SIS_MASK 0x00000008 +#define MCDE_SISPP_VSCC1SIS(__x) \ + MCDE_VAL2REG(MCDE_SISPP, VSCC1SIS, __x) +#define MCDE_SISPP_VCMPC0SIS_SHIFT 4 +#define MCDE_SISPP_VCMPC0SIS_MASK 0x00000010 +#define MCDE_SISPP_VCMPC0SIS(__x) \ + MCDE_VAL2REG(MCDE_SISPP, VCMPC0SIS, __x) +#define MCDE_SISPP_VCMPC1SIS_SHIFT 5 +#define MCDE_SISPP_VCMPC1SIS_MASK 0x00000020 +#define MCDE_SISPP_VCMPC1SIS(__x) \ + MCDE_VAL2REG(MCDE_SISPP, VCMPC1SIS, __x) +#define MCDE_SISPP_ROTFDSIS_A_SHIFT 6 +#define MCDE_SISPP_ROTFDSIS_A_MASK 0x00000040 +#define MCDE_SISPP_ROTFDSIS_A(__x) \ + MCDE_VAL2REG(MCDE_SISPP, ROTFDSIS_A, __x) +#define MCDE_SISPP_ROTFDSIS_B_SHIFT 7 +#define MCDE_SISPP_ROTFDSIS_B_MASK 0x00000080 +#define MCDE_SISPP_ROTFDSIS_B(__x) \ + MCDE_VAL2REG(MCDE_SISPP, ROTFDSIS_B, __x) +#define MCDE_SISOVL 0x00000138 +#define MCDE_SISOVL_OVLRDSIS_SHIFT 0 +#define MCDE_SISOVL_OVLRDSIS_MASK 0x0000FFFF +#define MCDE_SISOVL_OVLRDSIS(__x) \ + MCDE_VAL2REG(MCDE_SISOVL, OVLRDSIS, __x) +#define MCDE_SISOVL_OVLFDSIS_SHIFT 16 +#define MCDE_SISOVL_OVLFDSIS_MASK 0xFFFF0000 +#define MCDE_SISOVL_OVLFDSIS(__x) \ + MCDE_VAL2REG(MCDE_SISOVL, OVLFDSIS, __x) +#define MCDE_SISCHNL 0x0000013C +#define MCDE_SISCHNL_CHNLRDSIS_SHIFT 0 +#define MCDE_SISCHNL_CHNLRDSIS_MASK 0x0000FFFF +#define MCDE_SISCHNL_CHNLRDSIS(__x) \ + MCDE_VAL2REG(MCDE_SISCHNL, CHNLRDSIS, __x) +#define MCDE_SISCHNL_CHNLASIS_SHIFT 16 +#define MCDE_SISCHNL_CHNLASIS_MASK 0xFFFF0000 +#define MCDE_SISCHNL_CHNLASIS(__x) \ + MCDE_VAL2REG(MCDE_SISCHNL, CHNLASIS, __x) +#define MCDE_SISERR 0x00000140 +#define MCDE_SISERR_FUASIS_SHIFT 0 +#define MCDE_SISERR_FUASIS_MASK 0x00000001 +#define MCDE_SISERR_FUASIS(__x) \ + MCDE_VAL2REG(MCDE_SISERR, FUASIS, __x) +#define MCDE_SISERR_FUBSIS_SHIFT 1 +#define MCDE_SISERR_FUBSIS_MASK 0x00000002 +#define MCDE_SISERR_FUBSIS(__x) \ + MCDE_VAL2REG(MCDE_SISERR, FUBSIS, __x) +#define MCDE_SISERR_SCHBLCKDSIS_SHIFT 2 +#define MCDE_SISERR_SCHBLCKDSIS_MASK 0x00000004 +#define MCDE_SISERR_SCHBLCKDSIS(__x) \ + MCDE_VAL2REG(MCDE_SISERR, SCHBLCKDSIS, __x) +#define MCDE_SISERR_ROTAFESIS_WRITE_SHIFT 3 +#define MCDE_SISERR_ROTAFESIS_WRITE_MASK 0x00000008 +#define MCDE_SISERR_ROTAFESIS_WRITE(__x) \ + MCDE_VAL2REG(MCDE_SISERR, ROTAFESIS_WRITE, __x) +#define MCDE_SISERR_ROTAFESIS_READ_SHIFT 4 +#define MCDE_SISERR_ROTAFESIS_READ_MASK 0x00000010 +#define MCDE_SISERR_ROTAFESIS_READ(__x) \ + MCDE_VAL2REG(MCDE_SISERR, ROTAFESIS_READ, __x) +#define MCDE_SISERR_ROTBFESIS_WRITE_SHIFT 5 +#define MCDE_SISERR_ROTBFESIS_WRITE_MASK 0x00000020 +#define MCDE_SISERR_ROTBFESIS_WRITE(__x) \ + MCDE_VAL2REG(MCDE_SISERR, ROTBFESIS_WRITE, __x) +#define MCDE_SISERR_ROTBFESIS_READ_SHIFT 6 +#define MCDE_SISERR_ROTBFESIS_READ_MASK 0x00000040 +#define MCDE_SISERR_ROTBFESIS_READ(__x) \ + MCDE_VAL2REG(MCDE_SISERR, ROTBFESIS_READ, __x) +#define MCDE_SISERR_FUC0SIS_SHIFT 7 +#define MCDE_SISERR_FUC0SIS_MASK 0x00000080 +#define MCDE_SISERR_FUC0SIS(__x) \ + MCDE_VAL2REG(MCDE_SISERR, FUC0SIS, __x) +#define MCDE_SISERR_FUC1SIS_SHIFT 8 +#define MCDE_SISERR_FUC1SIS_MASK 0x00000100 +#define MCDE_SISERR_FUC1SIS(__x) \ + MCDE_VAL2REG(MCDE_SISERR, FUC1SIS, __x) +#define MCDE_SISERR_OVLFERSIS_SHIFT 16 +#define MCDE_SISERR_OVLFERSIS_MASK 0xFFFF0000 +#define MCDE_SISERR_OVLFERSIS(__x) \ + MCDE_VAL2REG(MCDE_SISERR, OVLFERSIS, __x) +#define MCDE_PID 0x000001FC +#define MCDE_PID_METALFIX_VERSION_SHIFT 0 +#define MCDE_PID_METALFIX_VERSION_MASK 0x000000FF +#define MCDE_PID_METALFIX_VERSION(__x) \ + MCDE_VAL2REG(MCDE_PID, METALFIX_VERSION, __x) +#define MCDE_PID_DEVELOPMENT_VERSION_SHIFT 8 +#define MCDE_PID_DEVELOPMENT_VERSION_MASK 0x0000FF00 +#define MCDE_PID_DEVELOPMENT_VERSION(__x) \ + MCDE_VAL2REG(MCDE_PID, DEVELOPMENT_VERSION, __x) +#define MCDE_PID_MINOR_VERSION_SHIFT 16 +#define MCDE_PID_MINOR_VERSION_MASK 0x00FF0000 +#define MCDE_PID_MINOR_VERSION(__x) \ + MCDE_VAL2REG(MCDE_PID, MINOR_VERSION, __x) +#define MCDE_PID_MAJOR_VERSION_SHIFT 24 +#define MCDE_PID_MAJOR_VERSION_MASK 0xFF000000 +#define MCDE_PID_MAJOR_VERSION(__x) \ + MCDE_VAL2REG(MCDE_PID, MAJOR_VERSION, __x) +#define MCDE_EXTSRC0A0 0x00000200 +#define MCDE_EXTSRC0A0_GROUPOFFSET 0x20 +#define MCDE_EXTSRC0A0_BASEADDRESS0_SHIFT 3 +#define MCDE_EXTSRC0A0_BASEADDRESS0_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC0A0_BASEADDRESS0(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0A0, BASEADDRESS0, __x) +#define MCDE_EXTSRC1A0 0x00000220 +#define MCDE_EXTSRC1A0_BASEADDRESS0_SHIFT 3 +#define MCDE_EXTSRC1A0_BASEADDRESS0_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC1A0_BASEADDRESS0(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1A0, BASEADDRESS0, __x) +#define MCDE_EXTSRC2A0 0x00000240 +#define MCDE_EXTSRC2A0_BASEADDRESS0_SHIFT 3 +#define MCDE_EXTSRC2A0_BASEADDRESS0_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC2A0_BASEADDRESS0(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2A0, BASEADDRESS0, __x) +#define MCDE_EXTSRC3A0 0x00000260 +#define MCDE_EXTSRC3A0_BASEADDRESS0_SHIFT 3 +#define MCDE_EXTSRC3A0_BASEADDRESS0_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC3A0_BASEADDRESS0(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3A0, BASEADDRESS0, __x) +#define MCDE_EXTSRC4A0 0x00000280 +#define MCDE_EXTSRC4A0_BASEADDRESS0_SHIFT 3 +#define MCDE_EXTSRC4A0_BASEADDRESS0_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC4A0_BASEADDRESS0(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4A0, BASEADDRESS0, __x) +#define MCDE_EXTSRC5A0 0x000002A0 +#define MCDE_EXTSRC5A0_BASEADDRESS0_SHIFT 3 +#define MCDE_EXTSRC5A0_BASEADDRESS0_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC5A0_BASEADDRESS0(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5A0, BASEADDRESS0, __x) +#define MCDE_EXTSRC6A0 0x000002C0 +#define MCDE_EXTSRC6A0_BASEADDRESS0_SHIFT 3 +#define MCDE_EXTSRC6A0_BASEADDRESS0_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC6A0_BASEADDRESS0(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6A0, BASEADDRESS0, __x) +#define MCDE_EXTSRC7A0 0x000002E0 +#define MCDE_EXTSRC7A0_BASEADDRESS0_SHIFT 3 +#define MCDE_EXTSRC7A0_BASEADDRESS0_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC7A0_BASEADDRESS0(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7A0, BASEADDRESS0, __x) +#define MCDE_EXTSRC8A0 0x00000300 +#define MCDE_EXTSRC8A0_BASEADDRESS0_SHIFT 3 +#define MCDE_EXTSRC8A0_BASEADDRESS0_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC8A0_BASEADDRESS0(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8A0, BASEADDRESS0, __x) +#define MCDE_EXTSRC9A0 0x00000320 +#define MCDE_EXTSRC9A0_BASEADDRESS0_SHIFT 3 +#define MCDE_EXTSRC9A0_BASEADDRESS0_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC9A0_BASEADDRESS0(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9A0, BASEADDRESS0, __x) +#define MCDE_EXTSRC0A1 0x00000204 +#define MCDE_EXTSRC0A1_GROUPOFFSET 0x20 +#define MCDE_EXTSRC0A1_BASEADDRESS1_SHIFT 3 +#define MCDE_EXTSRC0A1_BASEADDRESS1_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC0A1_BASEADDRESS1(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0A1, BASEADDRESS1, __x) +#define MCDE_EXTSRC1A1 0x00000224 +#define MCDE_EXTSRC1A1_BASEADDRESS1_SHIFT 3 +#define MCDE_EXTSRC1A1_BASEADDRESS1_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC1A1_BASEADDRESS1(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1A1, BASEADDRESS1, __x) +#define MCDE_EXTSRC2A1 0x00000244 +#define MCDE_EXTSRC2A1_BASEADDRESS1_SHIFT 3 +#define MCDE_EXTSRC2A1_BASEADDRESS1_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC2A1_BASEADDRESS1(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2A1, BASEADDRESS1, __x) +#define MCDE_EXTSRC3A1 0x00000264 +#define MCDE_EXTSRC3A1_BASEADDRESS1_SHIFT 3 +#define MCDE_EXTSRC3A1_BASEADDRESS1_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC3A1_BASEADDRESS1(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3A1, BASEADDRESS1, __x) +#define MCDE_EXTSRC4A1 0x00000284 +#define MCDE_EXTSRC4A1_BASEADDRESS1_SHIFT 3 +#define MCDE_EXTSRC4A1_BASEADDRESS1_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC4A1_BASEADDRESS1(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4A1, BASEADDRESS1, __x) +#define MCDE_EXTSRC5A1 0x000002A4 +#define MCDE_EXTSRC5A1_BASEADDRESS1_SHIFT 3 +#define MCDE_EXTSRC5A1_BASEADDRESS1_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC5A1_BASEADDRESS1(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5A1, BASEADDRESS1, __x) +#define MCDE_EXTSRC6A1 0x000002C4 +#define MCDE_EXTSRC6A1_BASEADDRESS1_SHIFT 3 +#define MCDE_EXTSRC6A1_BASEADDRESS1_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC6A1_BASEADDRESS1(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6A1, BASEADDRESS1, __x) +#define MCDE_EXTSRC7A1 0x000002E4 +#define MCDE_EXTSRC7A1_BASEADDRESS1_SHIFT 3 +#define MCDE_EXTSRC7A1_BASEADDRESS1_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC7A1_BASEADDRESS1(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7A1, BASEADDRESS1, __x) +#define MCDE_EXTSRC8A1 0x00000304 +#define MCDE_EXTSRC8A1_BASEADDRESS1_SHIFT 3 +#define MCDE_EXTSRC8A1_BASEADDRESS1_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC8A1_BASEADDRESS1(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8A1, BASEADDRESS1, __x) +#define MCDE_EXTSRC9A1 0x00000324 +#define MCDE_EXTSRC9A1_BASEADDRESS1_SHIFT 3 +#define MCDE_EXTSRC9A1_BASEADDRESS1_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC9A1_BASEADDRESS1(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9A1, BASEADDRESS1, __x) +#define MCDE_EXTSRC6A2 0x000002C8 +#define MCDE_EXTSRC6A2_BASEADDRESS2_SHIFT 3 +#define MCDE_EXTSRC6A2_BASEADDRESS2_MASK 0xFFFFFFF8 +#define MCDE_EXTSRC6A2_BASEADDRESS2(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6A2, BASEADDRESS2, __x) +#define MCDE_EXTSRC0CONF 0x0000020C +#define MCDE_EXTSRC0CONF_GROUPOFFSET 0x20 +#define MCDE_EXTSRC0CONF_BUF_ID_SHIFT 0 +#define MCDE_EXTSRC0CONF_BUF_ID_MASK 0x00000003 +#define MCDE_EXTSRC0CONF_BUF_ID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CONF, BUF_ID, __x) +#define MCDE_EXTSRC0CONF_BUF_NB_SHIFT 2 +#define MCDE_EXTSRC0CONF_BUF_NB_MASK 0x0000000C +#define MCDE_EXTSRC0CONF_BUF_NB(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CONF, BUF_NB, __x) +#define MCDE_EXTSRC0CONF_PRI_OVLID_SHIFT 4 +#define MCDE_EXTSRC0CONF_PRI_OVLID_MASK 0x000000F0 +#define MCDE_EXTSRC0CONF_PRI_OVLID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CONF, PRI_OVLID, __x) +#define MCDE_EXTSRC0CONF_BPP_SHIFT 8 +#define MCDE_EXTSRC0CONF_BPP_MASK 0x00000F00 +#define MCDE_EXTSRC0CONF_BPP_1BPP_PAL 0 +#define MCDE_EXTSRC0CONF_BPP_2BPP_PAL 1 +#define MCDE_EXTSRC0CONF_BPP_4BPP_PAL 2 +#define MCDE_EXTSRC0CONF_BPP_8BPP_PAL 3 +#define MCDE_EXTSRC0CONF_BPP_RGB444 4 +#define MCDE_EXTSRC0CONF_BPP_ARGB4444 5 +#define MCDE_EXTSRC0CONF_BPP_IRGB1555 6 +#define MCDE_EXTSRC0CONF_BPP_RGB565 7 +#define MCDE_EXTSRC0CONF_BPP_RGB888 8 +#define MCDE_EXTSRC0CONF_BPP_XRGB8888 9 +#define MCDE_EXTSRC0CONF_BPP_ARGB8888 10 +#define MCDE_EXTSRC0CONF_BPP_YCBCR422 11 +#define MCDE_EXTSRC0CONF_BPP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CONF, BPP, MCDE_EXTSRC0CONF_BPP_##__x) +#define MCDE_EXTSRC0CONF_BPP(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CONF, BPP, __x) +#define MCDE_EXTSRC0CONF_BGR_SHIFT 12 +#define MCDE_EXTSRC0CONF_BGR_MASK 0x00001000 +#define MCDE_EXTSRC0CONF_BGR_RGB 0 +#define MCDE_EXTSRC0CONF_BGR_BGR 1 +#define MCDE_EXTSRC0CONF_BGR_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CONF, BGR, MCDE_EXTSRC0CONF_BGR_##__x) +#define MCDE_EXTSRC0CONF_BGR(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CONF, BGR, __x) +#define MCDE_EXTSRC0CONF_BEBO_SHIFT 13 +#define MCDE_EXTSRC0CONF_BEBO_MASK 0x00002000 +#define MCDE_EXTSRC0CONF_BEBO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC0CONF_BEBO_BIG_ENDIAN 1 +#define MCDE_EXTSRC0CONF_BEBO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CONF, BEBO, MCDE_EXTSRC0CONF_BEBO_##__x) +#define MCDE_EXTSRC0CONF_BEBO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CONF, BEBO, __x) +#define MCDE_EXTSRC0CONF_BEPO_SHIFT 14 +#define MCDE_EXTSRC0CONF_BEPO_MASK 0x00004000 +#define MCDE_EXTSRC0CONF_BEPO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC0CONF_BEPO_BIG_ENDIAN 1 +#define MCDE_EXTSRC0CONF_BEPO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CONF, BEPO, MCDE_EXTSRC0CONF_BEPO_##__x) +#define MCDE_EXTSRC0CONF_BEPO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CONF, BEPO, __x) +#define MCDE_EXTSRC1CONF 0x0000022C +#define MCDE_EXTSRC1CONF_BUF_ID_SHIFT 0 +#define MCDE_EXTSRC1CONF_BUF_ID_MASK 0x00000003 +#define MCDE_EXTSRC1CONF_BUF_ID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CONF, BUF_ID, __x) +#define MCDE_EXTSRC1CONF_BUF_NB_SHIFT 2 +#define MCDE_EXTSRC1CONF_BUF_NB_MASK 0x0000000C +#define MCDE_EXTSRC1CONF_BUF_NB(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CONF, BUF_NB, __x) +#define MCDE_EXTSRC1CONF_PRI_OVLID_SHIFT 4 +#define MCDE_EXTSRC1CONF_PRI_OVLID_MASK 0x000000F0 +#define MCDE_EXTSRC1CONF_PRI_OVLID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CONF, PRI_OVLID, __x) +#define MCDE_EXTSRC1CONF_BPP_SHIFT 8 +#define MCDE_EXTSRC1CONF_BPP_MASK 0x00000F00 +#define MCDE_EXTSRC1CONF_BPP_1BPP_PAL 0 +#define MCDE_EXTSRC1CONF_BPP_2BPP_PAL 1 +#define MCDE_EXTSRC1CONF_BPP_4BPP_PAL 2 +#define MCDE_EXTSRC1CONF_BPP_8BPP_PAL 3 +#define MCDE_EXTSRC1CONF_BPP_RGB444 4 +#define MCDE_EXTSRC1CONF_BPP_ARGB4444 5 +#define MCDE_EXTSRC1CONF_BPP_IRGB1555 6 +#define MCDE_EXTSRC1CONF_BPP_RGB565 7 +#define MCDE_EXTSRC1CONF_BPP_RGB888 8 +#define MCDE_EXTSRC1CONF_BPP_XRGB8888 9 +#define MCDE_EXTSRC1CONF_BPP_ARGB8888 10 +#define MCDE_EXTSRC1CONF_BPP_YCBCR422 11 +#define MCDE_EXTSRC1CONF_BPP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CONF, BPP, MCDE_EXTSRC1CONF_BPP_##__x) +#define MCDE_EXTSRC1CONF_BPP(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CONF, BPP, __x) +#define MCDE_EXTSRC1CONF_BGR_SHIFT 12 +#define MCDE_EXTSRC1CONF_BGR_MASK 0x00001000 +#define MCDE_EXTSRC1CONF_BGR_RGB 0 +#define MCDE_EXTSRC1CONF_BGR_BGR 1 +#define MCDE_EXTSRC1CONF_BGR_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CONF, BGR, MCDE_EXTSRC1CONF_BGR_##__x) +#define MCDE_EXTSRC1CONF_BGR(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CONF, BGR, __x) +#define MCDE_EXTSRC1CONF_BEBO_SHIFT 13 +#define MCDE_EXTSRC1CONF_BEBO_MASK 0x00002000 +#define MCDE_EXTSRC1CONF_BEBO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC1CONF_BEBO_BIG_ENDIAN 1 +#define MCDE_EXTSRC1CONF_BEBO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CONF, BEBO, MCDE_EXTSRC1CONF_BEBO_##__x) +#define MCDE_EXTSRC1CONF_BEBO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CONF, BEBO, __x) +#define MCDE_EXTSRC1CONF_BEPO_SHIFT 14 +#define MCDE_EXTSRC1CONF_BEPO_MASK 0x00004000 +#define MCDE_EXTSRC1CONF_BEPO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC1CONF_BEPO_BIG_ENDIAN 1 +#define MCDE_EXTSRC1CONF_BEPO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CONF, BEPO, MCDE_EXTSRC1CONF_BEPO_##__x) +#define MCDE_EXTSRC1CONF_BEPO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CONF, BEPO, __x) +#define MCDE_EXTSRC2CONF 0x0000024C +#define MCDE_EXTSRC2CONF_BUF_ID_SHIFT 0 +#define MCDE_EXTSRC2CONF_BUF_ID_MASK 0x00000003 +#define MCDE_EXTSRC2CONF_BUF_ID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CONF, BUF_ID, __x) +#define MCDE_EXTSRC2CONF_BUF_NB_SHIFT 2 +#define MCDE_EXTSRC2CONF_BUF_NB_MASK 0x0000000C +#define MCDE_EXTSRC2CONF_BUF_NB(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CONF, BUF_NB, __x) +#define MCDE_EXTSRC2CONF_PRI_OVLID_SHIFT 4 +#define MCDE_EXTSRC2CONF_PRI_OVLID_MASK 0x000000F0 +#define MCDE_EXTSRC2CONF_PRI_OVLID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CONF, PRI_OVLID, __x) +#define MCDE_EXTSRC2CONF_BPP_SHIFT 8 +#define MCDE_EXTSRC2CONF_BPP_MASK 0x00000F00 +#define MCDE_EXTSRC2CONF_BPP_1BPP_PAL 0 +#define MCDE_EXTSRC2CONF_BPP_2BPP_PAL 1 +#define MCDE_EXTSRC2CONF_BPP_4BPP_PAL 2 +#define MCDE_EXTSRC2CONF_BPP_8BPP_PAL 3 +#define MCDE_EXTSRC2CONF_BPP_RGB444 4 +#define MCDE_EXTSRC2CONF_BPP_ARGB4444 5 +#define MCDE_EXTSRC2CONF_BPP_IRGB1555 6 +#define MCDE_EXTSRC2CONF_BPP_RGB565 7 +#define MCDE_EXTSRC2CONF_BPP_RGB888 8 +#define MCDE_EXTSRC2CONF_BPP_XRGB8888 9 +#define MCDE_EXTSRC2CONF_BPP_ARGB8888 10 +#define MCDE_EXTSRC2CONF_BPP_YCBCR422 11 +#define MCDE_EXTSRC2CONF_BPP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CONF, BPP, MCDE_EXTSRC2CONF_BPP_##__x) +#define MCDE_EXTSRC2CONF_BPP(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CONF, BPP, __x) +#define MCDE_EXTSRC2CONF_BGR_SHIFT 12 +#define MCDE_EXTSRC2CONF_BGR_MASK 0x00001000 +#define MCDE_EXTSRC2CONF_BGR_RGB 0 +#define MCDE_EXTSRC2CONF_BGR_BGR 1 +#define MCDE_EXTSRC2CONF_BGR_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CONF, BGR, MCDE_EXTSRC2CONF_BGR_##__x) +#define MCDE_EXTSRC2CONF_BGR(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CONF, BGR, __x) +#define MCDE_EXTSRC2CONF_BEBO_SHIFT 13 +#define MCDE_EXTSRC2CONF_BEBO_MASK 0x00002000 +#define MCDE_EXTSRC2CONF_BEBO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC2CONF_BEBO_BIG_ENDIAN 1 +#define MCDE_EXTSRC2CONF_BEBO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CONF, BEBO, MCDE_EXTSRC2CONF_BEBO_##__x) +#define MCDE_EXTSRC2CONF_BEBO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CONF, BEBO, __x) +#define MCDE_EXTSRC2CONF_BEPO_SHIFT 14 +#define MCDE_EXTSRC2CONF_BEPO_MASK 0x00004000 +#define MCDE_EXTSRC2CONF_BEPO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC2CONF_BEPO_BIG_ENDIAN 1 +#define MCDE_EXTSRC2CONF_BEPO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CONF, BEPO, MCDE_EXTSRC2CONF_BEPO_##__x) +#define MCDE_EXTSRC2CONF_BEPO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CONF, BEPO, __x) +#define MCDE_EXTSRC3CONF 0x0000026C +#define MCDE_EXTSRC3CONF_BUF_ID_SHIFT 0 +#define MCDE_EXTSRC3CONF_BUF_ID_MASK 0x00000003 +#define MCDE_EXTSRC3CONF_BUF_ID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CONF, BUF_ID, __x) +#define MCDE_EXTSRC3CONF_BUF_NB_SHIFT 2 +#define MCDE_EXTSRC3CONF_BUF_NB_MASK 0x0000000C +#define MCDE_EXTSRC3CONF_BUF_NB(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CONF, BUF_NB, __x) +#define MCDE_EXTSRC3CONF_PRI_OVLID_SHIFT 4 +#define MCDE_EXTSRC3CONF_PRI_OVLID_MASK 0x000000F0 +#define MCDE_EXTSRC3CONF_PRI_OVLID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CONF, PRI_OVLID, __x) +#define MCDE_EXTSRC3CONF_BPP_SHIFT 8 +#define MCDE_EXTSRC3CONF_BPP_MASK 0x00000F00 +#define MCDE_EXTSRC3CONF_BPP_1BPP_PAL 0 +#define MCDE_EXTSRC3CONF_BPP_2BPP_PAL 1 +#define MCDE_EXTSRC3CONF_BPP_4BPP_PAL 2 +#define MCDE_EXTSRC3CONF_BPP_8BPP_PAL 3 +#define MCDE_EXTSRC3CONF_BPP_RGB444 4 +#define MCDE_EXTSRC3CONF_BPP_ARGB4444 5 +#define MCDE_EXTSRC3CONF_BPP_IRGB1555 6 +#define MCDE_EXTSRC3CONF_BPP_RGB565 7 +#define MCDE_EXTSRC3CONF_BPP_RGB888 8 +#define MCDE_EXTSRC3CONF_BPP_XRGB8888 9 +#define MCDE_EXTSRC3CONF_BPP_ARGB8888 10 +#define MCDE_EXTSRC3CONF_BPP_YCBCR422 11 +#define MCDE_EXTSRC3CONF_BPP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CONF, BPP, MCDE_EXTSRC3CONF_BPP_##__x) +#define MCDE_EXTSRC3CONF_BPP(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CONF, BPP, __x) +#define MCDE_EXTSRC3CONF_BGR_SHIFT 12 +#define MCDE_EXTSRC3CONF_BGR_MASK 0x00001000 +#define MCDE_EXTSRC3CONF_BGR_RGB 0 +#define MCDE_EXTSRC3CONF_BGR_BGR 1 +#define MCDE_EXTSRC3CONF_BGR_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CONF, BGR, MCDE_EXTSRC3CONF_BGR_##__x) +#define MCDE_EXTSRC3CONF_BGR(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CONF, BGR, __x) +#define MCDE_EXTSRC3CONF_BEBO_SHIFT 13 +#define MCDE_EXTSRC3CONF_BEBO_MASK 0x00002000 +#define MCDE_EXTSRC3CONF_BEBO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC3CONF_BEBO_BIG_ENDIAN 1 +#define MCDE_EXTSRC3CONF_BEBO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CONF, BEBO, MCDE_EXTSRC3CONF_BEBO_##__x) +#define MCDE_EXTSRC3CONF_BEBO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CONF, BEBO, __x) +#define MCDE_EXTSRC3CONF_BEPO_SHIFT 14 +#define MCDE_EXTSRC3CONF_BEPO_MASK 0x00004000 +#define MCDE_EXTSRC3CONF_BEPO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC3CONF_BEPO_BIG_ENDIAN 1 +#define MCDE_EXTSRC3CONF_BEPO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CONF, BEPO, MCDE_EXTSRC3CONF_BEPO_##__x) +#define MCDE_EXTSRC3CONF_BEPO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CONF, BEPO, __x) +#define MCDE_EXTSRC4CONF 0x0000028C +#define MCDE_EXTSRC4CONF_BUF_ID_SHIFT 0 +#define MCDE_EXTSRC4CONF_BUF_ID_MASK 0x00000003 +#define MCDE_EXTSRC4CONF_BUF_ID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CONF, BUF_ID, __x) +#define MCDE_EXTSRC4CONF_BUF_NB_SHIFT 2 +#define MCDE_EXTSRC4CONF_BUF_NB_MASK 0x0000000C +#define MCDE_EXTSRC4CONF_BUF_NB(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CONF, BUF_NB, __x) +#define MCDE_EXTSRC4CONF_PRI_OVLID_SHIFT 4 +#define MCDE_EXTSRC4CONF_PRI_OVLID_MASK 0x000000F0 +#define MCDE_EXTSRC4CONF_PRI_OVLID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CONF, PRI_OVLID, __x) +#define MCDE_EXTSRC4CONF_BPP_SHIFT 8 +#define MCDE_EXTSRC4CONF_BPP_MASK 0x00000F00 +#define MCDE_EXTSRC4CONF_BPP_1BPP_PAL 0 +#define MCDE_EXTSRC4CONF_BPP_2BPP_PAL 1 +#define MCDE_EXTSRC4CONF_BPP_4BPP_PAL 2 +#define MCDE_EXTSRC4CONF_BPP_8BPP_PAL 3 +#define MCDE_EXTSRC4CONF_BPP_RGB444 4 +#define MCDE_EXTSRC4CONF_BPP_ARGB4444 5 +#define MCDE_EXTSRC4CONF_BPP_IRGB1555 6 +#define MCDE_EXTSRC4CONF_BPP_RGB565 7 +#define MCDE_EXTSRC4CONF_BPP_RGB888 8 +#define MCDE_EXTSRC4CONF_BPP_XRGB8888 9 +#define MCDE_EXTSRC4CONF_BPP_ARGB8888 10 +#define MCDE_EXTSRC4CONF_BPP_YCBCR422 11 +#define MCDE_EXTSRC4CONF_BPP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CONF, BPP, MCDE_EXTSRC4CONF_BPP_##__x) +#define MCDE_EXTSRC4CONF_BPP(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CONF, BPP, __x) +#define MCDE_EXTSRC4CONF_BGR_SHIFT 12 +#define MCDE_EXTSRC4CONF_BGR_MASK 0x00001000 +#define MCDE_EXTSRC4CONF_BGR_RGB 0 +#define MCDE_EXTSRC4CONF_BGR_BGR 1 +#define MCDE_EXTSRC4CONF_BGR_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CONF, BGR, MCDE_EXTSRC4CONF_BGR_##__x) +#define MCDE_EXTSRC4CONF_BGR(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CONF, BGR, __x) +#define MCDE_EXTSRC4CONF_BEBO_SHIFT 13 +#define MCDE_EXTSRC4CONF_BEBO_MASK 0x00002000 +#define MCDE_EXTSRC4CONF_BEBO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC4CONF_BEBO_BIG_ENDIAN 1 +#define MCDE_EXTSRC4CONF_BEBO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CONF, BEBO, MCDE_EXTSRC4CONF_BEBO_##__x) +#define MCDE_EXTSRC4CONF_BEBO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CONF, BEBO, __x) +#define MCDE_EXTSRC4CONF_BEPO_SHIFT 14 +#define MCDE_EXTSRC4CONF_BEPO_MASK 0x00004000 +#define MCDE_EXTSRC4CONF_BEPO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC4CONF_BEPO_BIG_ENDIAN 1 +#define MCDE_EXTSRC4CONF_BEPO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CONF, BEPO, MCDE_EXTSRC4CONF_BEPO_##__x) +#define MCDE_EXTSRC4CONF_BEPO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CONF, BEPO, __x) +#define MCDE_EXTSRC5CONF 0x000002AC +#define MCDE_EXTSRC5CONF_BUF_ID_SHIFT 0 +#define MCDE_EXTSRC5CONF_BUF_ID_MASK 0x00000003 +#define MCDE_EXTSRC5CONF_BUF_ID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CONF, BUF_ID, __x) +#define MCDE_EXTSRC5CONF_BUF_NB_SHIFT 2 +#define MCDE_EXTSRC5CONF_BUF_NB_MASK 0x0000000C +#define MCDE_EXTSRC5CONF_BUF_NB(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CONF, BUF_NB, __x) +#define MCDE_EXTSRC5CONF_PRI_OVLID_SHIFT 4 +#define MCDE_EXTSRC5CONF_PRI_OVLID_MASK 0x000000F0 +#define MCDE_EXTSRC5CONF_PRI_OVLID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CONF, PRI_OVLID, __x) +#define MCDE_EXTSRC5CONF_BPP_SHIFT 8 +#define MCDE_EXTSRC5CONF_BPP_MASK 0x00000F00 +#define MCDE_EXTSRC5CONF_BPP_1BPP_PAL 0 +#define MCDE_EXTSRC5CONF_BPP_2BPP_PAL 1 +#define MCDE_EXTSRC5CONF_BPP_4BPP_PAL 2 +#define MCDE_EXTSRC5CONF_BPP_8BPP_PAL 3 +#define MCDE_EXTSRC5CONF_BPP_RGB444 4 +#define MCDE_EXTSRC5CONF_BPP_ARGB4444 5 +#define MCDE_EXTSRC5CONF_BPP_IRGB1555 6 +#define MCDE_EXTSRC5CONF_BPP_RGB565 7 +#define MCDE_EXTSRC5CONF_BPP_RGB888 8 +#define MCDE_EXTSRC5CONF_BPP_XRGB8888 9 +#define MCDE_EXTSRC5CONF_BPP_ARGB8888 10 +#define MCDE_EXTSRC5CONF_BPP_YCBCR422 11 +#define MCDE_EXTSRC5CONF_BPP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CONF, BPP, MCDE_EXTSRC5CONF_BPP_##__x) +#define MCDE_EXTSRC5CONF_BPP(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CONF, BPP, __x) +#define MCDE_EXTSRC5CONF_BGR_SHIFT 12 +#define MCDE_EXTSRC5CONF_BGR_MASK 0x00001000 +#define MCDE_EXTSRC5CONF_BGR_RGB 0 +#define MCDE_EXTSRC5CONF_BGR_BGR 1 +#define MCDE_EXTSRC5CONF_BGR_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CONF, BGR, MCDE_EXTSRC5CONF_BGR_##__x) +#define MCDE_EXTSRC5CONF_BGR(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CONF, BGR, __x) +#define MCDE_EXTSRC5CONF_BEBO_SHIFT 13 +#define MCDE_EXTSRC5CONF_BEBO_MASK 0x00002000 +#define MCDE_EXTSRC5CONF_BEBO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC5CONF_BEBO_BIG_ENDIAN 1 +#define MCDE_EXTSRC5CONF_BEBO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CONF, BEBO, MCDE_EXTSRC5CONF_BEBO_##__x) +#define MCDE_EXTSRC5CONF_BEBO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CONF, BEBO, __x) +#define MCDE_EXTSRC5CONF_BEPO_SHIFT 14 +#define MCDE_EXTSRC5CONF_BEPO_MASK 0x00004000 +#define MCDE_EXTSRC5CONF_BEPO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC5CONF_BEPO_BIG_ENDIAN 1 +#define MCDE_EXTSRC5CONF_BEPO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CONF, BEPO, MCDE_EXTSRC5CONF_BEPO_##__x) +#define MCDE_EXTSRC5CONF_BEPO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CONF, BEPO, __x) +#define MCDE_EXTSRC6CONF 0x000002CC +#define MCDE_EXTSRC6CONF_BUF_ID_SHIFT 0 +#define MCDE_EXTSRC6CONF_BUF_ID_MASK 0x00000003 +#define MCDE_EXTSRC6CONF_BUF_ID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CONF, BUF_ID, __x) +#define MCDE_EXTSRC6CONF_BUF_NB_SHIFT 2 +#define MCDE_EXTSRC6CONF_BUF_NB_MASK 0x0000000C +#define MCDE_EXTSRC6CONF_BUF_NB(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CONF, BUF_NB, __x) +#define MCDE_EXTSRC6CONF_PRI_OVLID_SHIFT 4 +#define MCDE_EXTSRC6CONF_PRI_OVLID_MASK 0x000000F0 +#define MCDE_EXTSRC6CONF_PRI_OVLID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CONF, PRI_OVLID, __x) +#define MCDE_EXTSRC6CONF_BPP_SHIFT 8 +#define MCDE_EXTSRC6CONF_BPP_MASK 0x00000F00 +#define MCDE_EXTSRC6CONF_BPP_1BPP_PAL 0 +#define MCDE_EXTSRC6CONF_BPP_2BPP_PAL 1 +#define MCDE_EXTSRC6CONF_BPP_4BPP_PAL 2 +#define MCDE_EXTSRC6CONF_BPP_8BPP_PAL 3 +#define MCDE_EXTSRC6CONF_BPP_RGB444 4 +#define MCDE_EXTSRC6CONF_BPP_ARGB4444 5 +#define MCDE_EXTSRC6CONF_BPP_IRGB1555 6 +#define MCDE_EXTSRC6CONF_BPP_RGB565 7 +#define MCDE_EXTSRC6CONF_BPP_RGB888 8 +#define MCDE_EXTSRC6CONF_BPP_XRGB8888 9 +#define MCDE_EXTSRC6CONF_BPP_ARGB8888 10 +#define MCDE_EXTSRC6CONF_BPP_YCBCR422 11 +#define MCDE_EXTSRC6CONF_BPP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CONF, BPP, MCDE_EXTSRC6CONF_BPP_##__x) +#define MCDE_EXTSRC6CONF_BPP(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CONF, BPP, __x) +#define MCDE_EXTSRC6CONF_BGR_SHIFT 12 +#define MCDE_EXTSRC6CONF_BGR_MASK 0x00001000 +#define MCDE_EXTSRC6CONF_BGR_RGB 0 +#define MCDE_EXTSRC6CONF_BGR_BGR 1 +#define MCDE_EXTSRC6CONF_BGR_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CONF, BGR, MCDE_EXTSRC6CONF_BGR_##__x) +#define MCDE_EXTSRC6CONF_BGR(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CONF, BGR, __x) +#define MCDE_EXTSRC6CONF_BEBO_SHIFT 13 +#define MCDE_EXTSRC6CONF_BEBO_MASK 0x00002000 +#define MCDE_EXTSRC6CONF_BEBO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC6CONF_BEBO_BIG_ENDIAN 1 +#define MCDE_EXTSRC6CONF_BEBO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CONF, BEBO, MCDE_EXTSRC6CONF_BEBO_##__x) +#define MCDE_EXTSRC6CONF_BEBO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CONF, BEBO, __x) +#define MCDE_EXTSRC6CONF_BEPO_SHIFT 14 +#define MCDE_EXTSRC6CONF_BEPO_MASK 0x00004000 +#define MCDE_EXTSRC6CONF_BEPO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC6CONF_BEPO_BIG_ENDIAN 1 +#define MCDE_EXTSRC6CONF_BEPO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CONF, BEPO, MCDE_EXTSRC6CONF_BEPO_##__x) +#define MCDE_EXTSRC6CONF_BEPO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CONF, BEPO, __x) +#define MCDE_EXTSRC7CONF 0x000002EC +#define MCDE_EXTSRC7CONF_BUF_ID_SHIFT 0 +#define MCDE_EXTSRC7CONF_BUF_ID_MASK 0x00000003 +#define MCDE_EXTSRC7CONF_BUF_ID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CONF, BUF_ID, __x) +#define MCDE_EXTSRC7CONF_BUF_NB_SHIFT 2 +#define MCDE_EXTSRC7CONF_BUF_NB_MASK 0x0000000C +#define MCDE_EXTSRC7CONF_BUF_NB(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CONF, BUF_NB, __x) +#define MCDE_EXTSRC7CONF_PRI_OVLID_SHIFT 4 +#define MCDE_EXTSRC7CONF_PRI_OVLID_MASK 0x000000F0 +#define MCDE_EXTSRC7CONF_PRI_OVLID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CONF, PRI_OVLID, __x) +#define MCDE_EXTSRC7CONF_BPP_SHIFT 8 +#define MCDE_EXTSRC7CONF_BPP_MASK 0x00000F00 +#define MCDE_EXTSRC7CONF_BPP_1BPP_PAL 0 +#define MCDE_EXTSRC7CONF_BPP_2BPP_PAL 1 +#define MCDE_EXTSRC7CONF_BPP_4BPP_PAL 2 +#define MCDE_EXTSRC7CONF_BPP_8BPP_PAL 3 +#define MCDE_EXTSRC7CONF_BPP_RGB444 4 +#define MCDE_EXTSRC7CONF_BPP_ARGB4444 5 +#define MCDE_EXTSRC7CONF_BPP_IRGB1555 6 +#define MCDE_EXTSRC7CONF_BPP_RGB565 7 +#define MCDE_EXTSRC7CONF_BPP_RGB888 8 +#define MCDE_EXTSRC7CONF_BPP_XRGB8888 9 +#define MCDE_EXTSRC7CONF_BPP_ARGB8888 10 +#define MCDE_EXTSRC7CONF_BPP_YCBCR422 11 +#define MCDE_EXTSRC7CONF_BPP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CONF, BPP, MCDE_EXTSRC7CONF_BPP_##__x) +#define MCDE_EXTSRC7CONF_BPP(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CONF, BPP, __x) +#define MCDE_EXTSRC7CONF_BGR_SHIFT 12 +#define MCDE_EXTSRC7CONF_BGR_MASK 0x00001000 +#define MCDE_EXTSRC7CONF_BGR_RGB 0 +#define MCDE_EXTSRC7CONF_BGR_BGR 1 +#define MCDE_EXTSRC7CONF_BGR_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CONF, BGR, MCDE_EXTSRC7CONF_BGR_##__x) +#define MCDE_EXTSRC7CONF_BGR(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CONF, BGR, __x) +#define MCDE_EXTSRC7CONF_BEBO_SHIFT 13 +#define MCDE_EXTSRC7CONF_BEBO_MASK 0x00002000 +#define MCDE_EXTSRC7CONF_BEBO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC7CONF_BEBO_BIG_ENDIAN 1 +#define MCDE_EXTSRC7CONF_BEBO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CONF, BEBO, MCDE_EXTSRC7CONF_BEBO_##__x) +#define MCDE_EXTSRC7CONF_BEBO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CONF, BEBO, __x) +#define MCDE_EXTSRC7CONF_BEPO_SHIFT 14 +#define MCDE_EXTSRC7CONF_BEPO_MASK 0x00004000 +#define MCDE_EXTSRC7CONF_BEPO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC7CONF_BEPO_BIG_ENDIAN 1 +#define MCDE_EXTSRC7CONF_BEPO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CONF, BEPO, MCDE_EXTSRC7CONF_BEPO_##__x) +#define MCDE_EXTSRC7CONF_BEPO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CONF, BEPO, __x) +#define MCDE_EXTSRC8CONF 0x0000030C +#define MCDE_EXTSRC8CONF_BUF_ID_SHIFT 0 +#define MCDE_EXTSRC8CONF_BUF_ID_MASK 0x00000003 +#define MCDE_EXTSRC8CONF_BUF_ID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CONF, BUF_ID, __x) +#define MCDE_EXTSRC8CONF_BUF_NB_SHIFT 2 +#define MCDE_EXTSRC8CONF_BUF_NB_MASK 0x0000000C +#define MCDE_EXTSRC8CONF_BUF_NB(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CONF, BUF_NB, __x) +#define MCDE_EXTSRC8CONF_PRI_OVLID_SHIFT 4 +#define MCDE_EXTSRC8CONF_PRI_OVLID_MASK 0x000000F0 +#define MCDE_EXTSRC8CONF_PRI_OVLID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CONF, PRI_OVLID, __x) +#define MCDE_EXTSRC8CONF_BPP_SHIFT 8 +#define MCDE_EXTSRC8CONF_BPP_MASK 0x00000F00 +#define MCDE_EXTSRC8CONF_BPP_1BPP_PAL 0 +#define MCDE_EXTSRC8CONF_BPP_2BPP_PAL 1 +#define MCDE_EXTSRC8CONF_BPP_4BPP_PAL 2 +#define MCDE_EXTSRC8CONF_BPP_8BPP_PAL 3 +#define MCDE_EXTSRC8CONF_BPP_RGB444 4 +#define MCDE_EXTSRC8CONF_BPP_ARGB4444 5 +#define MCDE_EXTSRC8CONF_BPP_IRGB1555 6 +#define MCDE_EXTSRC8CONF_BPP_RGB565 7 +#define MCDE_EXTSRC8CONF_BPP_RGB888 8 +#define MCDE_EXTSRC8CONF_BPP_XRGB8888 9 +#define MCDE_EXTSRC8CONF_BPP_ARGB8888 10 +#define MCDE_EXTSRC8CONF_BPP_YCBCR422 11 +#define MCDE_EXTSRC8CONF_BPP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CONF, BPP, MCDE_EXTSRC8CONF_BPP_##__x) +#define MCDE_EXTSRC8CONF_BPP(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CONF, BPP, __x) +#define MCDE_EXTSRC8CONF_BGR_SHIFT 12 +#define MCDE_EXTSRC8CONF_BGR_MASK 0x00001000 +#define MCDE_EXTSRC8CONF_BGR_RGB 0 +#define MCDE_EXTSRC8CONF_BGR_BGR 1 +#define MCDE_EXTSRC8CONF_BGR_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CONF, BGR, MCDE_EXTSRC8CONF_BGR_##__x) +#define MCDE_EXTSRC8CONF_BGR(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CONF, BGR, __x) +#define MCDE_EXTSRC8CONF_BEBO_SHIFT 13 +#define MCDE_EXTSRC8CONF_BEBO_MASK 0x00002000 +#define MCDE_EXTSRC8CONF_BEBO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC8CONF_BEBO_BIG_ENDIAN 1 +#define MCDE_EXTSRC8CONF_BEBO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CONF, BEBO, MCDE_EXTSRC8CONF_BEBO_##__x) +#define MCDE_EXTSRC8CONF_BEBO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CONF, BEBO, __x) +#define MCDE_EXTSRC8CONF_BEPO_SHIFT 14 +#define MCDE_EXTSRC8CONF_BEPO_MASK 0x00004000 +#define MCDE_EXTSRC8CONF_BEPO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC8CONF_BEPO_BIG_ENDIAN 1 +#define MCDE_EXTSRC8CONF_BEPO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CONF, BEPO, MCDE_EXTSRC8CONF_BEPO_##__x) +#define MCDE_EXTSRC8CONF_BEPO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CONF, BEPO, __x) +#define MCDE_EXTSRC9CONF 0x0000032C +#define MCDE_EXTSRC9CONF_BUF_ID_SHIFT 0 +#define MCDE_EXTSRC9CONF_BUF_ID_MASK 0x00000003 +#define MCDE_EXTSRC9CONF_BUF_ID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CONF, BUF_ID, __x) +#define MCDE_EXTSRC9CONF_BUF_NB_SHIFT 2 +#define MCDE_EXTSRC9CONF_BUF_NB_MASK 0x0000000C +#define MCDE_EXTSRC9CONF_BUF_NB(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CONF, BUF_NB, __x) +#define MCDE_EXTSRC9CONF_PRI_OVLID_SHIFT 4 +#define MCDE_EXTSRC9CONF_PRI_OVLID_MASK 0x000000F0 +#define MCDE_EXTSRC9CONF_PRI_OVLID(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CONF, PRI_OVLID, __x) +#define MCDE_EXTSRC9CONF_BPP_SHIFT 8 +#define MCDE_EXTSRC9CONF_BPP_MASK 0x00000F00 +#define MCDE_EXTSRC9CONF_BPP_1BPP_PAL 0 +#define MCDE_EXTSRC9CONF_BPP_2BPP_PAL 1 +#define MCDE_EXTSRC9CONF_BPP_4BPP_PAL 2 +#define MCDE_EXTSRC9CONF_BPP_8BPP_PAL 3 +#define MCDE_EXTSRC9CONF_BPP_RGB444 4 +#define MCDE_EXTSRC9CONF_BPP_ARGB4444 5 +#define MCDE_EXTSRC9CONF_BPP_IRGB1555 6 +#define MCDE_EXTSRC9CONF_BPP_RGB565 7 +#define MCDE_EXTSRC9CONF_BPP_RGB888 8 +#define MCDE_EXTSRC9CONF_BPP_XRGB8888 9 +#define MCDE_EXTSRC9CONF_BPP_ARGB8888 10 +#define MCDE_EXTSRC9CONF_BPP_YCBCR422 11 +#define MCDE_EXTSRC9CONF_BPP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CONF, BPP, MCDE_EXTSRC9CONF_BPP_##__x) +#define MCDE_EXTSRC9CONF_BPP(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CONF, BPP, __x) +#define MCDE_EXTSRC9CONF_BGR_SHIFT 12 +#define MCDE_EXTSRC9CONF_BGR_MASK 0x00001000 +#define MCDE_EXTSRC9CONF_BGR_RGB 0 +#define MCDE_EXTSRC9CONF_BGR_BGR 1 +#define MCDE_EXTSRC9CONF_BGR_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CONF, BGR, MCDE_EXTSRC9CONF_BGR_##__x) +#define MCDE_EXTSRC9CONF_BGR(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CONF, BGR, __x) +#define MCDE_EXTSRC9CONF_BEBO_SHIFT 13 +#define MCDE_EXTSRC9CONF_BEBO_MASK 0x00002000 +#define MCDE_EXTSRC9CONF_BEBO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC9CONF_BEBO_BIG_ENDIAN 1 +#define MCDE_EXTSRC9CONF_BEBO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CONF, BEBO, MCDE_EXTSRC9CONF_BEBO_##__x) +#define MCDE_EXTSRC9CONF_BEBO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CONF, BEBO, __x) +#define MCDE_EXTSRC9CONF_BEPO_SHIFT 14 +#define MCDE_EXTSRC9CONF_BEPO_MASK 0x00004000 +#define MCDE_EXTSRC9CONF_BEPO_LITTLE_ENDIAN 0 +#define MCDE_EXTSRC9CONF_BEPO_BIG_ENDIAN 1 +#define MCDE_EXTSRC9CONF_BEPO_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CONF, BEPO, MCDE_EXTSRC9CONF_BEPO_##__x) +#define MCDE_EXTSRC9CONF_BEPO(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CONF, BEPO, __x) +#define MCDE_EXTSRC0CR 0x00000210 +#define MCDE_EXTSRC0CR_GROUPOFFSET 0x20 +#define MCDE_EXTSRC0CR_SEL_MOD_SHIFT 0 +#define MCDE_EXTSRC0CR_SEL_MOD_MASK 0x00000003 +#define MCDE_EXTSRC0CR_SEL_MOD_EXTERNAL_SEL 0 +#define MCDE_EXTSRC0CR_SEL_MOD_AUTO_TOGGLE 1 +#define MCDE_EXTSRC0CR_SEL_MOD_SOFTWARE_SEL 2 +#define MCDE_EXTSRC0CR_SEL_MOD_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CR, SEL_MOD, MCDE_EXTSRC0CR_SEL_MOD_##__x) +#define MCDE_EXTSRC0CR_SEL_MOD(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CR, SEL_MOD, __x) +#define MCDE_EXTSRC0CR_MULTIOVL_CTRL_SHIFT 2 +#define MCDE_EXTSRC0CR_MULTIOVL_CTRL_MASK 0x00000004 +#define MCDE_EXTSRC0CR_MULTIOVL_CTRL_ALL 0 +#define MCDE_EXTSRC0CR_MULTIOVL_CTRL_PRIMARY 1 +#define MCDE_EXTSRC0CR_MULTIOVL_CTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CR, MULTIOVL_CTRL, \ + MCDE_EXTSRC0CR_MULTIOVL_CTRL_##__x) +#define MCDE_EXTSRC0CR_MULTIOVL_CTRL(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CR, MULTIOVL_CTRL, __x) +#define MCDE_EXTSRC0CR_FS_DIV_DISABLE_SHIFT 3 +#define MCDE_EXTSRC0CR_FS_DIV_DISABLE_MASK 0x00000008 +#define MCDE_EXTSRC0CR_FS_DIV_DISABLE(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CR, FS_DIV_DISABLE, __x) +#define MCDE_EXTSRC0CR_FORCE_FS_DIV_SHIFT 4 +#define MCDE_EXTSRC0CR_FORCE_FS_DIV_MASK 0x00000010 +#define MCDE_EXTSRC0CR_FORCE_FS_DIV(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC0CR, FORCE_FS_DIV, __x) +#define MCDE_EXTSRC1CR 0x00000230 +#define MCDE_EXTSRC1CR_SEL_MOD_SHIFT 0 +#define MCDE_EXTSRC1CR_SEL_MOD_MASK 0x00000003 +#define MCDE_EXTSRC1CR_SEL_MOD_EXTERNAL_SEL 0 +#define MCDE_EXTSRC1CR_SEL_MOD_AUTO_TOGGLE 1 +#define MCDE_EXTSRC1CR_SEL_MOD_SOFTWARE_SEL 2 +#define MCDE_EXTSRC1CR_SEL_MOD_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CR, SEL_MOD, MCDE_EXTSRC1CR_SEL_MOD_##__x) +#define MCDE_EXTSRC1CR_SEL_MOD(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CR, SEL_MOD, __x) +#define MCDE_EXTSRC1CR_MULTIOVL_CTRL_SHIFT 2 +#define MCDE_EXTSRC1CR_MULTIOVL_CTRL_MASK 0x00000004 +#define MCDE_EXTSRC1CR_MULTIOVL_CTRL_ALL 0 +#define MCDE_EXTSRC1CR_MULTIOVL_CTRL_PRIMARY 1 +#define MCDE_EXTSRC1CR_MULTIOVL_CTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CR, MULTIOVL_CTRL, \ + MCDE_EXTSRC1CR_MULTIOVL_CTRL_##__x) +#define MCDE_EXTSRC1CR_MULTIOVL_CTRL(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CR, MULTIOVL_CTRL, __x) +#define MCDE_EXTSRC1CR_FS_DIV_DISABLE_SHIFT 3 +#define MCDE_EXTSRC1CR_FS_DIV_DISABLE_MASK 0x00000008 +#define MCDE_EXTSRC1CR_FS_DIV_DISABLE(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CR, FS_DIV_DISABLE, __x) +#define MCDE_EXTSRC1CR_FORCE_FS_DIV_SHIFT 4 +#define MCDE_EXTSRC1CR_FORCE_FS_DIV_MASK 0x00000010 +#define MCDE_EXTSRC1CR_FORCE_FS_DIV(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC1CR, FORCE_FS_DIV, __x) +#define MCDE_EXTSRC2CR 0x00000250 +#define MCDE_EXTSRC2CR_SEL_MOD_SHIFT 0 +#define MCDE_EXTSRC2CR_SEL_MOD_MASK 0x00000003 +#define MCDE_EXTSRC2CR_SEL_MOD_EXTERNAL_SEL 0 +#define MCDE_EXTSRC2CR_SEL_MOD_AUTO_TOGGLE 1 +#define MCDE_EXTSRC2CR_SEL_MOD_SOFTWARE_SEL 2 +#define MCDE_EXTSRC2CR_SEL_MOD_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CR, SEL_MOD, MCDE_EXTSRC2CR_SEL_MOD_##__x) +#define MCDE_EXTSRC2CR_SEL_MOD(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CR, SEL_MOD, __x) +#define MCDE_EXTSRC2CR_MULTIOVL_CTRL_SHIFT 2 +#define MCDE_EXTSRC2CR_MULTIOVL_CTRL_MASK 0x00000004 +#define MCDE_EXTSRC2CR_MULTIOVL_CTRL_ALL 0 +#define MCDE_EXTSRC2CR_MULTIOVL_CTRL_PRIMARY 1 +#define MCDE_EXTSRC2CR_MULTIOVL_CTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CR, MULTIOVL_CTRL, \ + MCDE_EXTSRC2CR_MULTIOVL_CTRL_##__x) +#define MCDE_EXTSRC2CR_MULTIOVL_CTRL(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CR, MULTIOVL_CTRL, __x) +#define MCDE_EXTSRC2CR_FS_DIV_DISABLE_SHIFT 3 +#define MCDE_EXTSRC2CR_FS_DIV_DISABLE_MASK 0x00000008 +#define MCDE_EXTSRC2CR_FS_DIV_DISABLE(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CR, FS_DIV_DISABLE, __x) +#define MCDE_EXTSRC2CR_FORCE_FS_DIV_SHIFT 4 +#define MCDE_EXTSRC2CR_FORCE_FS_DIV_MASK 0x00000010 +#define MCDE_EXTSRC2CR_FORCE_FS_DIV(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC2CR, FORCE_FS_DIV, __x) +#define MCDE_EXTSRC3CR 0x00000270 +#define MCDE_EXTSRC3CR_SEL_MOD_SHIFT 0 +#define MCDE_EXTSRC3CR_SEL_MOD_MASK 0x00000003 +#define MCDE_EXTSRC3CR_SEL_MOD_EXTERNAL_SEL 0 +#define MCDE_EXTSRC3CR_SEL_MOD_AUTO_TOGGLE 1 +#define MCDE_EXTSRC3CR_SEL_MOD_SOFTWARE_SEL 2 +#define MCDE_EXTSRC3CR_SEL_MOD_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CR, SEL_MOD, MCDE_EXTSRC3CR_SEL_MOD_##__x) +#define MCDE_EXTSRC3CR_SEL_MOD(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CR, SEL_MOD, __x) +#define MCDE_EXTSRC3CR_MULTIOVL_CTRL_SHIFT 2 +#define MCDE_EXTSRC3CR_MULTIOVL_CTRL_MASK 0x00000004 +#define MCDE_EXTSRC3CR_MULTIOVL_CTRL_ALL 0 +#define MCDE_EXTSRC3CR_MULTIOVL_CTRL_PRIMARY 1 +#define MCDE_EXTSRC3CR_MULTIOVL_CTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CR, MULTIOVL_CTRL, \ + MCDE_EXTSRC3CR_MULTIOVL_CTRL_##__x) +#define MCDE_EXTSRC3CR_MULTIOVL_CTRL(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CR, MULTIOVL_CTRL, __x) +#define MCDE_EXTSRC3CR_FS_DIV_DISABLE_SHIFT 3 +#define MCDE_EXTSRC3CR_FS_DIV_DISABLE_MASK 0x00000008 +#define MCDE_EXTSRC3CR_FS_DIV_DISABLE(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CR, FS_DIV_DISABLE, __x) +#define MCDE_EXTSRC3CR_FORCE_FS_DIV_SHIFT 4 +#define MCDE_EXTSRC3CR_FORCE_FS_DIV_MASK 0x00000010 +#define MCDE_EXTSRC3CR_FORCE_FS_DIV(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC3CR, FORCE_FS_DIV, __x) +#define MCDE_EXTSRC4CR 0x00000290 +#define MCDE_EXTSRC4CR_SEL_MOD_SHIFT 0 +#define MCDE_EXTSRC4CR_SEL_MOD_MASK 0x00000003 +#define MCDE_EXTSRC4CR_SEL_MOD_EXTERNAL_SEL 0 +#define MCDE_EXTSRC4CR_SEL_MOD_AUTO_TOGGLE 1 +#define MCDE_EXTSRC4CR_SEL_MOD_SOFTWARE_SEL 2 +#define MCDE_EXTSRC4CR_SEL_MOD_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CR, SEL_MOD, MCDE_EXTSRC4CR_SEL_MOD_##__x) +#define MCDE_EXTSRC4CR_SEL_MOD(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CR, SEL_MOD, __x) +#define MCDE_EXTSRC4CR_MULTIOVL_CTRL_SHIFT 2 +#define MCDE_EXTSRC4CR_MULTIOVL_CTRL_MASK 0x00000004 +#define MCDE_EXTSRC4CR_MULTIOVL_CTRL_ALL 0 +#define MCDE_EXTSRC4CR_MULTIOVL_CTRL_PRIMARY 1 +#define MCDE_EXTSRC4CR_MULTIOVL_CTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CR, MULTIOVL_CTRL, \ + MCDE_EXTSRC4CR_MULTIOVL_CTRL_##__x) +#define MCDE_EXTSRC4CR_MULTIOVL_CTRL(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CR, MULTIOVL_CTRL, __x) +#define MCDE_EXTSRC4CR_FS_DIV_DISABLE_SHIFT 3 +#define MCDE_EXTSRC4CR_FS_DIV_DISABLE_MASK 0x00000008 +#define MCDE_EXTSRC4CR_FS_DIV_DISABLE(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CR, FS_DIV_DISABLE, __x) +#define MCDE_EXTSRC4CR_FORCE_FS_DIV_SHIFT 4 +#define MCDE_EXTSRC4CR_FORCE_FS_DIV_MASK 0x00000010 +#define MCDE_EXTSRC4CR_FORCE_FS_DIV(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC4CR, FORCE_FS_DIV, __x) +#define MCDE_EXTSRC5CR 0x000002B0 +#define MCDE_EXTSRC5CR_SEL_MOD_SHIFT 0 +#define MCDE_EXTSRC5CR_SEL_MOD_MASK 0x00000003 +#define MCDE_EXTSRC5CR_SEL_MOD_EXTERNAL_SEL 0 +#define MCDE_EXTSRC5CR_SEL_MOD_AUTO_TOGGLE 1 +#define MCDE_EXTSRC5CR_SEL_MOD_SOFTWARE_SEL 2 +#define MCDE_EXTSRC5CR_SEL_MOD_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CR, SEL_MOD, MCDE_EXTSRC5CR_SEL_MOD_##__x) +#define MCDE_EXTSRC5CR_SEL_MOD(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CR, SEL_MOD, __x) +#define MCDE_EXTSRC5CR_MULTIOVL_CTRL_SHIFT 2 +#define MCDE_EXTSRC5CR_MULTIOVL_CTRL_MASK 0x00000004 +#define MCDE_EXTSRC5CR_MULTIOVL_CTRL_ALL 0 +#define MCDE_EXTSRC5CR_MULTIOVL_CTRL_PRIMARY 1 +#define MCDE_EXTSRC5CR_MULTIOVL_CTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CR, MULTIOVL_CTRL, \ + MCDE_EXTSRC5CR_MULTIOVL_CTRL_##__x) +#define MCDE_EXTSRC5CR_MULTIOVL_CTRL(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CR, MULTIOVL_CTRL, __x) +#define MCDE_EXTSRC5CR_FS_DIV_DISABLE_SHIFT 3 +#define MCDE_EXTSRC5CR_FS_DIV_DISABLE_MASK 0x00000008 +#define MCDE_EXTSRC5CR_FS_DIV_DISABLE(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CR, FS_DIV_DISABLE, __x) +#define MCDE_EXTSRC5CR_FORCE_FS_DIV_SHIFT 4 +#define MCDE_EXTSRC5CR_FORCE_FS_DIV_MASK 0x00000010 +#define MCDE_EXTSRC5CR_FORCE_FS_DIV(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC5CR, FORCE_FS_DIV, __x) +#define MCDE_EXTSRC6CR 0x000002D0 +#define MCDE_EXTSRC6CR_SEL_MOD_SHIFT 0 +#define MCDE_EXTSRC6CR_SEL_MOD_MASK 0x00000003 +#define MCDE_EXTSRC6CR_SEL_MOD_EXTERNAL_SEL 0 +#define MCDE_EXTSRC6CR_SEL_MOD_AUTO_TOGGLE 1 +#define MCDE_EXTSRC6CR_SEL_MOD_SOFTWARE_SEL 2 +#define MCDE_EXTSRC6CR_SEL_MOD_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CR, SEL_MOD, MCDE_EXTSRC6CR_SEL_MOD_##__x) +#define MCDE_EXTSRC6CR_SEL_MOD(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CR, SEL_MOD, __x) +#define MCDE_EXTSRC6CR_MULTIOVL_CTRL_SHIFT 2 +#define MCDE_EXTSRC6CR_MULTIOVL_CTRL_MASK 0x00000004 +#define MCDE_EXTSRC6CR_MULTIOVL_CTRL_ALL 0 +#define MCDE_EXTSRC6CR_MULTIOVL_CTRL_PRIMARY 1 +#define MCDE_EXTSRC6CR_MULTIOVL_CTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CR, MULTIOVL_CTRL, \ + MCDE_EXTSRC6CR_MULTIOVL_CTRL_##__x) +#define MCDE_EXTSRC6CR_MULTIOVL_CTRL(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CR, MULTIOVL_CTRL, __x) +#define MCDE_EXTSRC6CR_FS_DIV_DISABLE_SHIFT 3 +#define MCDE_EXTSRC6CR_FS_DIV_DISABLE_MASK 0x00000008 +#define MCDE_EXTSRC6CR_FS_DIV_DISABLE(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CR, FS_DIV_DISABLE, __x) +#define MCDE_EXTSRC6CR_FORCE_FS_DIV_SHIFT 4 +#define MCDE_EXTSRC6CR_FORCE_FS_DIV_MASK 0x00000010 +#define MCDE_EXTSRC6CR_FORCE_FS_DIV(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC6CR, FORCE_FS_DIV, __x) +#define MCDE_EXTSRC7CR 0x000002F0 +#define MCDE_EXTSRC7CR_SEL_MOD_SHIFT 0 +#define MCDE_EXTSRC7CR_SEL_MOD_MASK 0x00000003 +#define MCDE_EXTSRC7CR_SEL_MOD_EXTERNAL_SEL 0 +#define MCDE_EXTSRC7CR_SEL_MOD_AUTO_TOGGLE 1 +#define MCDE_EXTSRC7CR_SEL_MOD_SOFTWARE_SEL 2 +#define MCDE_EXTSRC7CR_SEL_MOD_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CR, SEL_MOD, MCDE_EXTSRC7CR_SEL_MOD_##__x) +#define MCDE_EXTSRC7CR_SEL_MOD(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CR, SEL_MOD, __x) +#define MCDE_EXTSRC7CR_MULTIOVL_CTRL_SHIFT 2 +#define MCDE_EXTSRC7CR_MULTIOVL_CTRL_MASK 0x00000004 +#define MCDE_EXTSRC7CR_MULTIOVL_CTRL_ALL 0 +#define MCDE_EXTSRC7CR_MULTIOVL_CTRL_PRIMARY 1 +#define MCDE_EXTSRC7CR_MULTIOVL_CTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CR, MULTIOVL_CTRL, \ + MCDE_EXTSRC7CR_MULTIOVL_CTRL_##__x) +#define MCDE_EXTSRC7CR_MULTIOVL_CTRL(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CR, MULTIOVL_CTRL, __x) +#define MCDE_EXTSRC7CR_FS_DIV_DISABLE_SHIFT 3 +#define MCDE_EXTSRC7CR_FS_DIV_DISABLE_MASK 0x00000008 +#define MCDE_EXTSRC7CR_FS_DIV_DISABLE(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CR, FS_DIV_DISABLE, __x) +#define MCDE_EXTSRC7CR_FORCE_FS_DIV_SHIFT 4 +#define MCDE_EXTSRC7CR_FORCE_FS_DIV_MASK 0x00000010 +#define MCDE_EXTSRC7CR_FORCE_FS_DIV(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC7CR, FORCE_FS_DIV, __x) +#define MCDE_EXTSRC8CR 0x00000310 +#define MCDE_EXTSRC8CR_SEL_MOD_SHIFT 0 +#define MCDE_EXTSRC8CR_SEL_MOD_MASK 0x00000003 +#define MCDE_EXTSRC8CR_SEL_MOD_EXTERNAL_SEL 0 +#define MCDE_EXTSRC8CR_SEL_MOD_AUTO_TOGGLE 1 +#define MCDE_EXTSRC8CR_SEL_MOD_SOFTWARE_SEL 2 +#define MCDE_EXTSRC8CR_SEL_MOD_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CR, SEL_MOD, MCDE_EXTSRC8CR_SEL_MOD_##__x) +#define MCDE_EXTSRC8CR_SEL_MOD(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CR, SEL_MOD, __x) +#define MCDE_EXTSRC8CR_MULTIOVL_CTRL_SHIFT 2 +#define MCDE_EXTSRC8CR_MULTIOVL_CTRL_MASK 0x00000004 +#define MCDE_EXTSRC8CR_MULTIOVL_CTRL_ALL 0 +#define MCDE_EXTSRC8CR_MULTIOVL_CTRL_PRIMARY 1 +#define MCDE_EXTSRC8CR_MULTIOVL_CTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CR, MULTIOVL_CTRL, \ + MCDE_EXTSRC8CR_MULTIOVL_CTRL_##__x) +#define MCDE_EXTSRC8CR_MULTIOVL_CTRL(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CR, MULTIOVL_CTRL, __x) +#define MCDE_EXTSRC8CR_FS_DIV_DISABLE_SHIFT 3 +#define MCDE_EXTSRC8CR_FS_DIV_DISABLE_MASK 0x00000008 +#define MCDE_EXTSRC8CR_FS_DIV_DISABLE(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CR, FS_DIV_DISABLE, __x) +#define MCDE_EXTSRC8CR_FORCE_FS_DIV_SHIFT 4 +#define MCDE_EXTSRC8CR_FORCE_FS_DIV_MASK 0x00000010 +#define MCDE_EXTSRC8CR_FORCE_FS_DIV(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC8CR, FORCE_FS_DIV, __x) +#define MCDE_EXTSRC9CR 0x00000330 +#define MCDE_EXTSRC9CR_SEL_MOD_SHIFT 0 +#define MCDE_EXTSRC9CR_SEL_MOD_MASK 0x00000003 +#define MCDE_EXTSRC9CR_SEL_MOD_EXTERNAL_SEL 0 +#define MCDE_EXTSRC9CR_SEL_MOD_AUTO_TOGGLE 1 +#define MCDE_EXTSRC9CR_SEL_MOD_SOFTWARE_SEL 2 +#define MCDE_EXTSRC9CR_SEL_MOD_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CR, SEL_MOD, MCDE_EXTSRC9CR_SEL_MOD_##__x) +#define MCDE_EXTSRC9CR_SEL_MOD(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CR, SEL_MOD, __x) +#define MCDE_EXTSRC9CR_MULTIOVL_CTRL_SHIFT 2 +#define MCDE_EXTSRC9CR_MULTIOVL_CTRL_MASK 0x00000004 +#define MCDE_EXTSRC9CR_MULTIOVL_CTRL_ALL 0 +#define MCDE_EXTSRC9CR_MULTIOVL_CTRL_PRIMARY 1 +#define MCDE_EXTSRC9CR_MULTIOVL_CTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CR, MULTIOVL_CTRL, \ + MCDE_EXTSRC9CR_MULTIOVL_CTRL_##__x) +#define MCDE_EXTSRC9CR_MULTIOVL_CTRL(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CR, MULTIOVL_CTRL, __x) +#define MCDE_EXTSRC9CR_FS_DIV_DISABLE_SHIFT 3 +#define MCDE_EXTSRC9CR_FS_DIV_DISABLE_MASK 0x00000008 +#define MCDE_EXTSRC9CR_FS_DIV_DISABLE(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CR, FS_DIV_DISABLE, __x) +#define MCDE_EXTSRC9CR_FORCE_FS_DIV_SHIFT 4 +#define MCDE_EXTSRC9CR_FORCE_FS_DIV_MASK 0x00000010 +#define MCDE_EXTSRC9CR_FORCE_FS_DIV(__x) \ + MCDE_VAL2REG(MCDE_EXTSRC9CR, FORCE_FS_DIV, __x) +#define MCDE_OVL0CR 0x00000400 +#define MCDE_OVL0CR_GROUPOFFSET 0x20 +#define MCDE_OVL0CR_OVLEN_SHIFT 0 +#define MCDE_OVL0CR_OVLEN_MASK 0x00000001 +#define MCDE_OVL0CR_OVLEN(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, OVLEN, __x) +#define MCDE_OVL0CR_COLCCTRL_SHIFT 1 +#define MCDE_OVL0CR_COLCCTRL_MASK 0x00000006 +#define MCDE_OVL0CR_COLCCTRL_DISABLED 0 +#define MCDE_OVL0CR_COLCCTRL_ENABLED_NO_SAT 1 +#define MCDE_OVL0CR_COLCCTRL_ENABLED_SAT 2 +#define MCDE_OVL0CR_COLCCTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, COLCCTRL, MCDE_OVL0CR_COLCCTRL_##__x) +#define MCDE_OVL0CR_COLCCTRL(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, COLCCTRL, __x) +#define MCDE_OVL0CR_CKEYGEN_SHIFT 3 +#define MCDE_OVL0CR_CKEYGEN_MASK 0x00000008 +#define MCDE_OVL0CR_CKEYGEN(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, CKEYGEN, __x) +#define MCDE_OVL0CR_ALPHAPMEN_SHIFT 4 +#define MCDE_OVL0CR_ALPHAPMEN_MASK 0x00000010 +#define MCDE_OVL0CR_ALPHAPMEN(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, ALPHAPMEN, __x) +#define MCDE_OVL0CR_OVLF_SHIFT 5 +#define MCDE_OVL0CR_OVLF_MASK 0x00000020 +#define MCDE_OVL0CR_OVLF(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, OVLF, __x) +#define MCDE_OVL0CR_OVLR_SHIFT 6 +#define MCDE_OVL0CR_OVLR_MASK 0x00000040 +#define MCDE_OVL0CR_OVLR(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, OVLR, __x) +#define MCDE_OVL0CR_OVLB_SHIFT 7 +#define MCDE_OVL0CR_OVLB_MASK 0x00000080 +#define MCDE_OVL0CR_OVLB(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, OVLB, __x) +#define MCDE_OVL0CR_FETCH_ROPC_SHIFT 8 +#define MCDE_OVL0CR_FETCH_ROPC_MASK 0x0000FF00 +#define MCDE_OVL0CR_FETCH_ROPC(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, FETCH_ROPC, __x) +#define MCDE_OVL0CR_STBPRIO_SHIFT 16 +#define MCDE_OVL0CR_STBPRIO_MASK 0x000F0000 +#define MCDE_OVL0CR_STBPRIO(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, STBPRIO, __x) +#define MCDE_OVL0CR_BURSTSIZE_SHIFT 20 +#define MCDE_OVL0CR_BURSTSIZE_MASK 0x00F00000 +#define MCDE_OVL0CR_BURSTSIZE_1W 0 +#define MCDE_OVL0CR_BURSTSIZE_2W 1 +#define MCDE_OVL0CR_BURSTSIZE_4W 2 +#define MCDE_OVL0CR_BURSTSIZE_8W 3 +#define MCDE_OVL0CR_BURSTSIZE_16W 4 +#define MCDE_OVL0CR_BURSTSIZE_HW_1W 8 +#define MCDE_OVL0CR_BURSTSIZE_HW_2W 9 +#define MCDE_OVL0CR_BURSTSIZE_HW_4W 10 +#define MCDE_OVL0CR_BURSTSIZE_HW_8W 11 +#define MCDE_OVL0CR_BURSTSIZE_HW_16W 12 +#define MCDE_OVL0CR_BURSTSIZE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, BURSTSIZE, MCDE_OVL0CR_BURSTSIZE_##__x) +#define MCDE_OVL0CR_BURSTSIZE(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, BURSTSIZE, __x) +#define MCDE_OVL0CR_MAXOUTSTANDING_SHIFT 24 +#define MCDE_OVL0CR_MAXOUTSTANDING_MASK 0x0F000000 +#define MCDE_OVL0CR_MAXOUTSTANDING_1_REQ 0 +#define MCDE_OVL0CR_MAXOUTSTANDING_2_REQ 1 +#define MCDE_OVL0CR_MAXOUTSTANDING_4_REQ 2 +#define MCDE_OVL0CR_MAXOUTSTANDING_8_REQ 3 +#define MCDE_OVL0CR_MAXOUTSTANDING_16_REQ 4 +#define MCDE_OVL0CR_MAXOUTSTANDING_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, MAXOUTSTANDING, \ + MCDE_OVL0CR_MAXOUTSTANDING_##__x) +#define MCDE_OVL0CR_MAXOUTSTANDING(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, MAXOUTSTANDING, __x) +#define MCDE_OVL0CR_ROTBURSTSIZE_SHIFT 28 +#define MCDE_OVL0CR_ROTBURSTSIZE_MASK 0xF0000000 +#define MCDE_OVL0CR_ROTBURSTSIZE_1W 0 +#define MCDE_OVL0CR_ROTBURSTSIZE_2W 1 +#define MCDE_OVL0CR_ROTBURSTSIZE_4W 2 +#define MCDE_OVL0CR_ROTBURSTSIZE_8W 3 +#define MCDE_OVL0CR_ROTBURSTSIZE_16W 4 +#define MCDE_OVL0CR_ROTBURSTSIZE_HW_1W 8 +#define MCDE_OVL0CR_ROTBURSTSIZE_HW_2W 9 +#define MCDE_OVL0CR_ROTBURSTSIZE_HW_4W 10 +#define MCDE_OVL0CR_ROTBURSTSIZE_HW_8W 11 +#define MCDE_OVL0CR_ROTBURSTSIZE_HW_16W 12 +#define MCDE_OVL0CR_ROTBURSTSIZE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, ROTBURSTSIZE, MCDE_OVL0CR_ROTBURSTSIZE_##__x) +#define MCDE_OVL0CR_ROTBURSTSIZE(__x) \ + MCDE_VAL2REG(MCDE_OVL0CR, ROTBURSTSIZE, __x) +#define MCDE_OVL1CR 0x00000420 +#define MCDE_OVL1CR_OVLEN_SHIFT 0 +#define MCDE_OVL1CR_OVLEN_MASK 0x00000001 +#define MCDE_OVL1CR_OVLEN(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, OVLEN, __x) +#define MCDE_OVL1CR_COLCCTRL_SHIFT 1 +#define MCDE_OVL1CR_COLCCTRL_MASK 0x00000006 +#define MCDE_OVL1CR_COLCCTRL_DISABLED 0 +#define MCDE_OVL1CR_COLCCTRL_ENABLED_NO_SAT 1 +#define MCDE_OVL1CR_COLCCTRL_ENABLED_SAT 2 +#define MCDE_OVL1CR_COLCCTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, COLCCTRL, MCDE_OVL1CR_COLCCTRL_##__x) +#define MCDE_OVL1CR_COLCCTRL(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, COLCCTRL, __x) +#define MCDE_OVL1CR_CKEYGEN_SHIFT 3 +#define MCDE_OVL1CR_CKEYGEN_MASK 0x00000008 +#define MCDE_OVL1CR_CKEYGEN(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, CKEYGEN, __x) +#define MCDE_OVL1CR_ALPHAPMEN_SHIFT 4 +#define MCDE_OVL1CR_ALPHAPMEN_MASK 0x00000010 +#define MCDE_OVL1CR_ALPHAPMEN(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, ALPHAPMEN, __x) +#define MCDE_OVL1CR_OVLF_SHIFT 5 +#define MCDE_OVL1CR_OVLF_MASK 0x00000020 +#define MCDE_OVL1CR_OVLF(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, OVLF, __x) +#define MCDE_OVL1CR_OVLR_SHIFT 6 +#define MCDE_OVL1CR_OVLR_MASK 0x00000040 +#define MCDE_OVL1CR_OVLR(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, OVLR, __x) +#define MCDE_OVL1CR_OVLB_SHIFT 7 +#define MCDE_OVL1CR_OVLB_MASK 0x00000080 +#define MCDE_OVL1CR_OVLB(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, OVLB, __x) +#define MCDE_OVL1CR_FETCH_ROPC_SHIFT 8 +#define MCDE_OVL1CR_FETCH_ROPC_MASK 0x0000FF00 +#define MCDE_OVL1CR_FETCH_ROPC(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, FETCH_ROPC, __x) +#define MCDE_OVL1CR_STBPRIO_SHIFT 16 +#define MCDE_OVL1CR_STBPRIO_MASK 0x000F0000 +#define MCDE_OVL1CR_STBPRIO(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, STBPRIO, __x) +#define MCDE_OVL1CR_BURSTSIZE_SHIFT 20 +#define MCDE_OVL1CR_BURSTSIZE_MASK 0x00F00000 +#define MCDE_OVL1CR_BURSTSIZE_1W 0 +#define MCDE_OVL1CR_BURSTSIZE_2W 1 +#define MCDE_OVL1CR_BURSTSIZE_4W 2 +#define MCDE_OVL1CR_BURSTSIZE_8W 3 +#define MCDE_OVL1CR_BURSTSIZE_16W 4 +#define MCDE_OVL1CR_BURSTSIZE_HW_1W 8 +#define MCDE_OVL1CR_BURSTSIZE_HW_2W 9 +#define MCDE_OVL1CR_BURSTSIZE_HW_4W 10 +#define MCDE_OVL1CR_BURSTSIZE_HW_8W 11 +#define MCDE_OVL1CR_BURSTSIZE_HW_16W 12 +#define MCDE_OVL1CR_BURSTSIZE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, BURSTSIZE, MCDE_OVL1CR_BURSTSIZE_##__x) +#define MCDE_OVL1CR_BURSTSIZE(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, BURSTSIZE, __x) +#define MCDE_OVL1CR_MAXOUTSTANDING_SHIFT 24 +#define MCDE_OVL1CR_MAXOUTSTANDING_MASK 0x0F000000 +#define MCDE_OVL1CR_MAXOUTSTANDING_1_REQ 0 +#define MCDE_OVL1CR_MAXOUTSTANDING_2_REQ 1 +#define MCDE_OVL1CR_MAXOUTSTANDING_4_REQ 2 +#define MCDE_OVL1CR_MAXOUTSTANDING_8_REQ 3 +#define MCDE_OVL1CR_MAXOUTSTANDING_16_REQ 4 +#define MCDE_OVL1CR_MAXOUTSTANDING_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, MAXOUTSTANDING, \ + MCDE_OVL1CR_MAXOUTSTANDING_##__x) +#define MCDE_OVL1CR_MAXOUTSTANDING(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, MAXOUTSTANDING, __x) +#define MCDE_OVL1CR_ROTBURSTSIZE_SHIFT 28 +#define MCDE_OVL1CR_ROTBURSTSIZE_MASK 0xF0000000 +#define MCDE_OVL1CR_ROTBURSTSIZE_1W 0 +#define MCDE_OVL1CR_ROTBURSTSIZE_2W 1 +#define MCDE_OVL1CR_ROTBURSTSIZE_4W 2 +#define MCDE_OVL1CR_ROTBURSTSIZE_8W 3 +#define MCDE_OVL1CR_ROTBURSTSIZE_16W 4 +#define MCDE_OVL1CR_ROTBURSTSIZE_HW_1W 8 +#define MCDE_OVL1CR_ROTBURSTSIZE_HW_2W 9 +#define MCDE_OVL1CR_ROTBURSTSIZE_HW_4W 10 +#define MCDE_OVL1CR_ROTBURSTSIZE_HW_8W 11 +#define MCDE_OVL1CR_ROTBURSTSIZE_HW_16W 12 +#define MCDE_OVL1CR_ROTBURSTSIZE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, ROTBURSTSIZE, MCDE_OVL1CR_ROTBURSTSIZE_##__x) +#define MCDE_OVL1CR_ROTBURSTSIZE(__x) \ + MCDE_VAL2REG(MCDE_OVL1CR, ROTBURSTSIZE, __x) +#define MCDE_OVL2CR 0x00000440 +#define MCDE_OVL2CR_OVLEN_SHIFT 0 +#define MCDE_OVL2CR_OVLEN_MASK 0x00000001 +#define MCDE_OVL2CR_OVLEN(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, OVLEN, __x) +#define MCDE_OVL2CR_COLCCTRL_SHIFT 1 +#define MCDE_OVL2CR_COLCCTRL_MASK 0x00000006 +#define MCDE_OVL2CR_COLCCTRL_DISABLED 0 +#define MCDE_OVL2CR_COLCCTRL_ENABLED_NO_SAT 1 +#define MCDE_OVL2CR_COLCCTRL_ENABLED_SAT 2 +#define MCDE_OVL2CR_COLCCTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, COLCCTRL, MCDE_OVL2CR_COLCCTRL_##__x) +#define MCDE_OVL2CR_COLCCTRL(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, COLCCTRL, __x) +#define MCDE_OVL2CR_CKEYGEN_SHIFT 3 +#define MCDE_OVL2CR_CKEYGEN_MASK 0x00000008 +#define MCDE_OVL2CR_CKEYGEN(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, CKEYGEN, __x) +#define MCDE_OVL2CR_ALPHAPMEN_SHIFT 4 +#define MCDE_OVL2CR_ALPHAPMEN_MASK 0x00000010 +#define MCDE_OVL2CR_ALPHAPMEN(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, ALPHAPMEN, __x) +#define MCDE_OVL2CR_OVLF_SHIFT 5 +#define MCDE_OVL2CR_OVLF_MASK 0x00000020 +#define MCDE_OVL2CR_OVLF(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, OVLF, __x) +#define MCDE_OVL2CR_OVLR_SHIFT 6 +#define MCDE_OVL2CR_OVLR_MASK 0x00000040 +#define MCDE_OVL2CR_OVLR(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, OVLR, __x) +#define MCDE_OVL2CR_OVLB_SHIFT 7 +#define MCDE_OVL2CR_OVLB_MASK 0x00000080 +#define MCDE_OVL2CR_OVLB(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, OVLB, __x) +#define MCDE_OVL2CR_FETCH_ROPC_SHIFT 8 +#define MCDE_OVL2CR_FETCH_ROPC_MASK 0x0000FF00 +#define MCDE_OVL2CR_FETCH_ROPC(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, FETCH_ROPC, __x) +#define MCDE_OVL2CR_STBPRIO_SHIFT 16 +#define MCDE_OVL2CR_STBPRIO_MASK 0x000F0000 +#define MCDE_OVL2CR_STBPRIO(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, STBPRIO, __x) +#define MCDE_OVL2CR_BURSTSIZE_SHIFT 20 +#define MCDE_OVL2CR_BURSTSIZE_MASK 0x00F00000 +#define MCDE_OVL2CR_BURSTSIZE_1W 0 +#define MCDE_OVL2CR_BURSTSIZE_2W 1 +#define MCDE_OVL2CR_BURSTSIZE_4W 2 +#define MCDE_OVL2CR_BURSTSIZE_8W 3 +#define MCDE_OVL2CR_BURSTSIZE_16W 4 +#define MCDE_OVL2CR_BURSTSIZE_HW_1W 8 +#define MCDE_OVL2CR_BURSTSIZE_HW_2W 9 +#define MCDE_OVL2CR_BURSTSIZE_HW_4W 10 +#define MCDE_OVL2CR_BURSTSIZE_HW_8W 11 +#define MCDE_OVL2CR_BURSTSIZE_HW_16W 12 +#define MCDE_OVL2CR_BURSTSIZE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, BURSTSIZE, MCDE_OVL2CR_BURSTSIZE_##__x) +#define MCDE_OVL2CR_BURSTSIZE(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, BURSTSIZE, __x) +#define MCDE_OVL2CR_MAXOUTSTANDING_SHIFT 24 +#define MCDE_OVL2CR_MAXOUTSTANDING_MASK 0x0F000000 +#define MCDE_OVL2CR_MAXOUTSTANDING_1_REQ 0 +#define MCDE_OVL2CR_MAXOUTSTANDING_2_REQ 1 +#define MCDE_OVL2CR_MAXOUTSTANDING_4_REQ 2 +#define MCDE_OVL2CR_MAXOUTSTANDING_8_REQ 3 +#define MCDE_OVL2CR_MAXOUTSTANDING_16_REQ 4 +#define MCDE_OVL2CR_MAXOUTSTANDING_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, MAXOUTSTANDING, \ + MCDE_OVL2CR_MAXOUTSTANDING_##__x) +#define MCDE_OVL2CR_MAXOUTSTANDING(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, MAXOUTSTANDING, __x) +#define MCDE_OVL2CR_ROTBURSTSIZE_SHIFT 28 +#define MCDE_OVL2CR_ROTBURSTSIZE_MASK 0xF0000000 +#define MCDE_OVL2CR_ROTBURSTSIZE_1W 0 +#define MCDE_OVL2CR_ROTBURSTSIZE_2W 1 +#define MCDE_OVL2CR_ROTBURSTSIZE_4W 2 +#define MCDE_OVL2CR_ROTBURSTSIZE_8W 3 +#define MCDE_OVL2CR_ROTBURSTSIZE_16W 4 +#define MCDE_OVL2CR_ROTBURSTSIZE_HW_1W 8 +#define MCDE_OVL2CR_ROTBURSTSIZE_HW_2W 9 +#define MCDE_OVL2CR_ROTBURSTSIZE_HW_4W 10 +#define MCDE_OVL2CR_ROTBURSTSIZE_HW_8W 11 +#define MCDE_OVL2CR_ROTBURSTSIZE_HW_16W 12 +#define MCDE_OVL2CR_ROTBURSTSIZE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, ROTBURSTSIZE, MCDE_OVL2CR_ROTBURSTSIZE_##__x) +#define MCDE_OVL2CR_ROTBURSTSIZE(__x) \ + MCDE_VAL2REG(MCDE_OVL2CR, ROTBURSTSIZE, __x) +#define MCDE_OVL3CR 0x00000460 +#define MCDE_OVL3CR_OVLEN_SHIFT 0 +#define MCDE_OVL3CR_OVLEN_MASK 0x00000001 +#define MCDE_OVL3CR_OVLEN(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, OVLEN, __x) +#define MCDE_OVL3CR_COLCCTRL_SHIFT 1 +#define MCDE_OVL3CR_COLCCTRL_MASK 0x00000006 +#define MCDE_OVL3CR_COLCCTRL_DISABLED 0 +#define MCDE_OVL3CR_COLCCTRL_ENABLED_NO_SAT 1 +#define MCDE_OVL3CR_COLCCTRL_ENABLED_SAT 2 +#define MCDE_OVL3CR_COLCCTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, COLCCTRL, MCDE_OVL3CR_COLCCTRL_##__x) +#define MCDE_OVL3CR_COLCCTRL(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, COLCCTRL, __x) +#define MCDE_OVL3CR_CKEYGEN_SHIFT 3 +#define MCDE_OVL3CR_CKEYGEN_MASK 0x00000008 +#define MCDE_OVL3CR_CKEYGEN(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, CKEYGEN, __x) +#define MCDE_OVL3CR_ALPHAPMEN_SHIFT 4 +#define MCDE_OVL3CR_ALPHAPMEN_MASK 0x00000010 +#define MCDE_OVL3CR_ALPHAPMEN(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, ALPHAPMEN, __x) +#define MCDE_OVL3CR_OVLF_SHIFT 5 +#define MCDE_OVL3CR_OVLF_MASK 0x00000020 +#define MCDE_OVL3CR_OVLF(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, OVLF, __x) +#define MCDE_OVL3CR_OVLR_SHIFT 6 +#define MCDE_OVL3CR_OVLR_MASK 0x00000040 +#define MCDE_OVL3CR_OVLR(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, OVLR, __x) +#define MCDE_OVL3CR_OVLB_SHIFT 7 +#define MCDE_OVL3CR_OVLB_MASK 0x00000080 +#define MCDE_OVL3CR_OVLB(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, OVLB, __x) +#define MCDE_OVL3CR_FETCH_ROPC_SHIFT 8 +#define MCDE_OVL3CR_FETCH_ROPC_MASK 0x0000FF00 +#define MCDE_OVL3CR_FETCH_ROPC(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, FETCH_ROPC, __x) +#define MCDE_OVL3CR_STBPRIO_SHIFT 16 +#define MCDE_OVL3CR_STBPRIO_MASK 0x000F0000 +#define MCDE_OVL3CR_STBPRIO(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, STBPRIO, __x) +#define MCDE_OVL3CR_BURSTSIZE_SHIFT 20 +#define MCDE_OVL3CR_BURSTSIZE_MASK 0x00F00000 +#define MCDE_OVL3CR_BURSTSIZE_1W 0 +#define MCDE_OVL3CR_BURSTSIZE_2W 1 +#define MCDE_OVL3CR_BURSTSIZE_4W 2 +#define MCDE_OVL3CR_BURSTSIZE_8W 3 +#define MCDE_OVL3CR_BURSTSIZE_16W 4 +#define MCDE_OVL3CR_BURSTSIZE_HW_1W 8 +#define MCDE_OVL3CR_BURSTSIZE_HW_2W 9 +#define MCDE_OVL3CR_BURSTSIZE_HW_4W 10 +#define MCDE_OVL3CR_BURSTSIZE_HW_8W 11 +#define MCDE_OVL3CR_BURSTSIZE_HW_16W 12 +#define MCDE_OVL3CR_BURSTSIZE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, BURSTSIZE, MCDE_OVL3CR_BURSTSIZE_##__x) +#define MCDE_OVL3CR_BURSTSIZE(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, BURSTSIZE, __x) +#define MCDE_OVL3CR_MAXOUTSTANDING_SHIFT 24 +#define MCDE_OVL3CR_MAXOUTSTANDING_MASK 0x0F000000 +#define MCDE_OVL3CR_MAXOUTSTANDING_1_REQ 0 +#define MCDE_OVL3CR_MAXOUTSTANDING_2_REQ 1 +#define MCDE_OVL3CR_MAXOUTSTANDING_4_REQ 2 +#define MCDE_OVL3CR_MAXOUTSTANDING_8_REQ 3 +#define MCDE_OVL3CR_MAXOUTSTANDING_16_REQ 4 +#define MCDE_OVL3CR_MAXOUTSTANDING_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, MAXOUTSTANDING, \ + MCDE_OVL3CR_MAXOUTSTANDING_##__x) +#define MCDE_OVL3CR_MAXOUTSTANDING(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, MAXOUTSTANDING, __x) +#define MCDE_OVL3CR_ROTBURSTSIZE_SHIFT 28 +#define MCDE_OVL3CR_ROTBURSTSIZE_MASK 0xF0000000 +#define MCDE_OVL3CR_ROTBURSTSIZE_1W 0 +#define MCDE_OVL3CR_ROTBURSTSIZE_2W 1 +#define MCDE_OVL3CR_ROTBURSTSIZE_4W 2 +#define MCDE_OVL3CR_ROTBURSTSIZE_8W 3 +#define MCDE_OVL3CR_ROTBURSTSIZE_16W 4 +#define MCDE_OVL3CR_ROTBURSTSIZE_HW_1W 8 +#define MCDE_OVL3CR_ROTBURSTSIZE_HW_2W 9 +#define MCDE_OVL3CR_ROTBURSTSIZE_HW_4W 10 +#define MCDE_OVL3CR_ROTBURSTSIZE_HW_8W 11 +#define MCDE_OVL3CR_ROTBURSTSIZE_HW_16W 12 +#define MCDE_OVL3CR_ROTBURSTSIZE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, ROTBURSTSIZE, MCDE_OVL3CR_ROTBURSTSIZE_##__x) +#define MCDE_OVL3CR_ROTBURSTSIZE(__x) \ + MCDE_VAL2REG(MCDE_OVL3CR, ROTBURSTSIZE, __x) +#define MCDE_OVL4CR 0x00000480 +#define MCDE_OVL4CR_OVLEN_SHIFT 0 +#define MCDE_OVL4CR_OVLEN_MASK 0x00000001 +#define MCDE_OVL4CR_OVLEN(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, OVLEN, __x) +#define MCDE_OVL4CR_COLCCTRL_SHIFT 1 +#define MCDE_OVL4CR_COLCCTRL_MASK 0x00000006 +#define MCDE_OVL4CR_COLCCTRL_DISABLED 0 +#define MCDE_OVL4CR_COLCCTRL_ENABLED_NO_SAT 1 +#define MCDE_OVL4CR_COLCCTRL_ENABLED_SAT 2 +#define MCDE_OVL4CR_COLCCTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, COLCCTRL, MCDE_OVL4CR_COLCCTRL_##__x) +#define MCDE_OVL4CR_COLCCTRL(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, COLCCTRL, __x) +#define MCDE_OVL4CR_CKEYGEN_SHIFT 3 +#define MCDE_OVL4CR_CKEYGEN_MASK 0x00000008 +#define MCDE_OVL4CR_CKEYGEN(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, CKEYGEN, __x) +#define MCDE_OVL4CR_ALPHAPMEN_SHIFT 4 +#define MCDE_OVL4CR_ALPHAPMEN_MASK 0x00000010 +#define MCDE_OVL4CR_ALPHAPMEN(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, ALPHAPMEN, __x) +#define MCDE_OVL4CR_OVLF_SHIFT 5 +#define MCDE_OVL4CR_OVLF_MASK 0x00000020 +#define MCDE_OVL4CR_OVLF(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, OVLF, __x) +#define MCDE_OVL4CR_OVLR_SHIFT 6 +#define MCDE_OVL4CR_OVLR_MASK 0x00000040 +#define MCDE_OVL4CR_OVLR(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, OVLR, __x) +#define MCDE_OVL4CR_OVLB_SHIFT 7 +#define MCDE_OVL4CR_OVLB_MASK 0x00000080 +#define MCDE_OVL4CR_OVLB(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, OVLB, __x) +#define MCDE_OVL4CR_FETCH_ROPC_SHIFT 8 +#define MCDE_OVL4CR_FETCH_ROPC_MASK 0x0000FF00 +#define MCDE_OVL4CR_FETCH_ROPC(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, FETCH_ROPC, __x) +#define MCDE_OVL4CR_STBPRIO_SHIFT 16 +#define MCDE_OVL4CR_STBPRIO_MASK 0x000F0000 +#define MCDE_OVL4CR_STBPRIO(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, STBPRIO, __x) +#define MCDE_OVL4CR_BURSTSIZE_SHIFT 20 +#define MCDE_OVL4CR_BURSTSIZE_MASK 0x00F00000 +#define MCDE_OVL4CR_BURSTSIZE_1W 0 +#define MCDE_OVL4CR_BURSTSIZE_2W 1 +#define MCDE_OVL4CR_BURSTSIZE_4W 2 +#define MCDE_OVL4CR_BURSTSIZE_8W 3 +#define MCDE_OVL4CR_BURSTSIZE_16W 4 +#define MCDE_OVL4CR_BURSTSIZE_HW_1W 8 +#define MCDE_OVL4CR_BURSTSIZE_HW_2W 9 +#define MCDE_OVL4CR_BURSTSIZE_HW_4W 10 +#define MCDE_OVL4CR_BURSTSIZE_HW_8W 11 +#define MCDE_OVL4CR_BURSTSIZE_HW_16W 12 +#define MCDE_OVL4CR_BURSTSIZE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, BURSTSIZE, MCDE_OVL4CR_BURSTSIZE_##__x) +#define MCDE_OVL4CR_BURSTSIZE(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, BURSTSIZE, __x) +#define MCDE_OVL4CR_MAXOUTSTANDING_SHIFT 24 +#define MCDE_OVL4CR_MAXOUTSTANDING_MASK 0x0F000000 +#define MCDE_OVL4CR_MAXOUTSTANDING_1_REQ 0 +#define MCDE_OVL4CR_MAXOUTSTANDING_2_REQ 1 +#define MCDE_OVL4CR_MAXOUTSTANDING_4_REQ 2 +#define MCDE_OVL4CR_MAXOUTSTANDING_8_REQ 3 +#define MCDE_OVL4CR_MAXOUTSTANDING_16_REQ 4 +#define MCDE_OVL4CR_MAXOUTSTANDING_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, MAXOUTSTANDING, \ + MCDE_OVL4CR_MAXOUTSTANDING_##__x) +#define MCDE_OVL4CR_MAXOUTSTANDING(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, MAXOUTSTANDING, __x) +#define MCDE_OVL4CR_ROTBURSTSIZE_SHIFT 28 +#define MCDE_OVL4CR_ROTBURSTSIZE_MASK 0xF0000000 +#define MCDE_OVL4CR_ROTBURSTSIZE_1W 0 +#define MCDE_OVL4CR_ROTBURSTSIZE_2W 1 +#define MCDE_OVL4CR_ROTBURSTSIZE_4W 2 +#define MCDE_OVL4CR_ROTBURSTSIZE_8W 3 +#define MCDE_OVL4CR_ROTBURSTSIZE_16W 4 +#define MCDE_OVL4CR_ROTBURSTSIZE_HW_1W 8 +#define MCDE_OVL4CR_ROTBURSTSIZE_HW_2W 9 +#define MCDE_OVL4CR_ROTBURSTSIZE_HW_4W 10 +#define MCDE_OVL4CR_ROTBURSTSIZE_HW_8W 11 +#define MCDE_OVL4CR_ROTBURSTSIZE_HW_16W 12 +#define MCDE_OVL4CR_ROTBURSTSIZE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, ROTBURSTSIZE, MCDE_OVL4CR_ROTBURSTSIZE_##__x) +#define MCDE_OVL4CR_ROTBURSTSIZE(__x) \ + MCDE_VAL2REG(MCDE_OVL4CR, ROTBURSTSIZE, __x) +#define MCDE_OVL5CR 0x000004A0 +#define MCDE_OVL5CR_OVLEN_SHIFT 0 +#define MCDE_OVL5CR_OVLEN_MASK 0x00000001 +#define MCDE_OVL5CR_OVLEN(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, OVLEN, __x) +#define MCDE_OVL5CR_COLCCTRL_SHIFT 1 +#define MCDE_OVL5CR_COLCCTRL_MASK 0x00000006 +#define MCDE_OVL5CR_COLCCTRL_DISABLED 0 +#define MCDE_OVL5CR_COLCCTRL_ENABLED_NO_SAT 1 +#define MCDE_OVL5CR_COLCCTRL_ENABLED_SAT 2 +#define MCDE_OVL5CR_COLCCTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, COLCCTRL, MCDE_OVL5CR_COLCCTRL_##__x) +#define MCDE_OVL5CR_COLCCTRL(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, COLCCTRL, __x) +#define MCDE_OVL5CR_CKEYGEN_SHIFT 3 +#define MCDE_OVL5CR_CKEYGEN_MASK 0x00000008 +#define MCDE_OVL5CR_CKEYGEN(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, CKEYGEN, __x) +#define MCDE_OVL5CR_ALPHAPMEN_SHIFT 4 +#define MCDE_OVL5CR_ALPHAPMEN_MASK 0x00000010 +#define MCDE_OVL5CR_ALPHAPMEN(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, ALPHAPMEN, __x) +#define MCDE_OVL5CR_OVLF_SHIFT 5 +#define MCDE_OVL5CR_OVLF_MASK 0x00000020 +#define MCDE_OVL5CR_OVLF(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, OVLF, __x) +#define MCDE_OVL5CR_OVLR_SHIFT 6 +#define MCDE_OVL5CR_OVLR_MASK 0x00000040 +#define MCDE_OVL5CR_OVLR(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, OVLR, __x) +#define MCDE_OVL5CR_OVLB_SHIFT 7 +#define MCDE_OVL5CR_OVLB_MASK 0x00000080 +#define MCDE_OVL5CR_OVLB(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, OVLB, __x) +#define MCDE_OVL5CR_FETCH_ROPC_SHIFT 8 +#define MCDE_OVL5CR_FETCH_ROPC_MASK 0x0000FF00 +#define MCDE_OVL5CR_FETCH_ROPC(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, FETCH_ROPC, __x) +#define MCDE_OVL5CR_STBPRIO_SHIFT 16 +#define MCDE_OVL5CR_STBPRIO_MASK 0x000F0000 +#define MCDE_OVL5CR_STBPRIO(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, STBPRIO, __x) +#define MCDE_OVL5CR_BURSTSIZE_SHIFT 20 +#define MCDE_OVL5CR_BURSTSIZE_MASK 0x00F00000 +#define MCDE_OVL5CR_BURSTSIZE_1W 0 +#define MCDE_OVL5CR_BURSTSIZE_2W 1 +#define MCDE_OVL5CR_BURSTSIZE_4W 2 +#define MCDE_OVL5CR_BURSTSIZE_8W 3 +#define MCDE_OVL5CR_BURSTSIZE_16W 4 +#define MCDE_OVL5CR_BURSTSIZE_HW_1W 8 +#define MCDE_OVL5CR_BURSTSIZE_HW_2W 9 +#define MCDE_OVL5CR_BURSTSIZE_HW_4W 10 +#define MCDE_OVL5CR_BURSTSIZE_HW_8W 11 +#define MCDE_OVL5CR_BURSTSIZE_HW_16W 12 +#define MCDE_OVL5CR_BURSTSIZE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, BURSTSIZE, MCDE_OVL5CR_BURSTSIZE_##__x) +#define MCDE_OVL5CR_BURSTSIZE(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, BURSTSIZE, __x) +#define MCDE_OVL5CR_MAXOUTSTANDING_SHIFT 24 +#define MCDE_OVL5CR_MAXOUTSTANDING_MASK 0x0F000000 +#define MCDE_OVL5CR_MAXOUTSTANDING_1_REQ 0 +#define MCDE_OVL5CR_MAXOUTSTANDING_2_REQ 1 +#define MCDE_OVL5CR_MAXOUTSTANDING_4_REQ 2 +#define MCDE_OVL5CR_MAXOUTSTANDING_8_REQ 3 +#define MCDE_OVL5CR_MAXOUTSTANDING_16_REQ 4 +#define MCDE_OVL5CR_MAXOUTSTANDING_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, MAXOUTSTANDING, \ + MCDE_OVL5CR_MAXOUTSTANDING_##__x) +#define MCDE_OVL5CR_MAXOUTSTANDING(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, MAXOUTSTANDING, __x) +#define MCDE_OVL5CR_ROTBURSTSIZE_SHIFT 28 +#define MCDE_OVL5CR_ROTBURSTSIZE_MASK 0xF0000000 +#define MCDE_OVL5CR_ROTBURSTSIZE_1W 0 +#define MCDE_OVL5CR_ROTBURSTSIZE_2W 1 +#define MCDE_OVL5CR_ROTBURSTSIZE_4W 2 +#define MCDE_OVL5CR_ROTBURSTSIZE_8W 3 +#define MCDE_OVL5CR_ROTBURSTSIZE_16W 4 +#define MCDE_OVL5CR_ROTBURSTSIZE_HW_1W 8 +#define MCDE_OVL5CR_ROTBURSTSIZE_HW_2W 9 +#define MCDE_OVL5CR_ROTBURSTSIZE_HW_4W 10 +#define MCDE_OVL5CR_ROTBURSTSIZE_HW_8W 11 +#define MCDE_OVL5CR_ROTBURSTSIZE_HW_16W 12 +#define MCDE_OVL5CR_ROTBURSTSIZE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, ROTBURSTSIZE, MCDE_OVL5CR_ROTBURSTSIZE_##__x) +#define MCDE_OVL5CR_ROTBURSTSIZE(__x) \ + MCDE_VAL2REG(MCDE_OVL5CR, ROTBURSTSIZE, __x) +#define MCDE_OVL0CONF 0x00000404 +#define MCDE_OVL0CONF_GROUPOFFSET 0x20 +#define MCDE_OVL0CONF_PPL_SHIFT 0 +#define MCDE_OVL0CONF_PPL_MASK 0x000007FF +#define MCDE_OVL0CONF_PPL(__x) \ + MCDE_VAL2REG(MCDE_OVL0CONF, PPL, __x) +#define MCDE_OVL0CONF_EXTSRC_ID_SHIFT 11 +#define MCDE_OVL0CONF_EXTSRC_ID_MASK 0x00007800 +#define MCDE_OVL0CONF_EXTSRC_ID(__x) \ + MCDE_VAL2REG(MCDE_OVL0CONF, EXTSRC_ID, __x) +#define MCDE_OVL0CONF_LPF_SHIFT 16 +#define MCDE_OVL0CONF_LPF_MASK 0x07FF0000 +#define MCDE_OVL0CONF_LPF(__x) \ + MCDE_VAL2REG(MCDE_OVL0CONF, LPF, __x) +#define MCDE_OVL1CONF 0x00000424 +#define MCDE_OVL1CONF_PPL_SHIFT 0 +#define MCDE_OVL1CONF_PPL_MASK 0x000007FF +#define MCDE_OVL1CONF_PPL(__x) \ + MCDE_VAL2REG(MCDE_OVL1CONF, PPL, __x) +#define MCDE_OVL1CONF_EXTSRC_ID_SHIFT 11 +#define MCDE_OVL1CONF_EXTSRC_ID_MASK 0x00007800 +#define MCDE_OVL1CONF_EXTSRC_ID(__x) \ + MCDE_VAL2REG(MCDE_OVL1CONF, EXTSRC_ID, __x) +#define MCDE_OVL1CONF_LPF_SHIFT 16 +#define MCDE_OVL1CONF_LPF_MASK 0x07FF0000 +#define MCDE_OVL1CONF_LPF(__x) \ + MCDE_VAL2REG(MCDE_OVL1CONF, LPF, __x) +#define MCDE_OVL2CONF 0x00000444 +#define MCDE_OVL2CONF_PPL_SHIFT 0 +#define MCDE_OVL2CONF_PPL_MASK 0x000007FF +#define MCDE_OVL2CONF_PPL(__x) \ + MCDE_VAL2REG(MCDE_OVL2CONF, PPL, __x) +#define MCDE_OVL2CONF_EXTSRC_ID_SHIFT 11 +#define MCDE_OVL2CONF_EXTSRC_ID_MASK 0x00007800 +#define MCDE_OVL2CONF_EXTSRC_ID(__x) \ + MCDE_VAL2REG(MCDE_OVL2CONF, EXTSRC_ID, __x) +#define MCDE_OVL2CONF_LPF_SHIFT 16 +#define MCDE_OVL2CONF_LPF_MASK 0x07FF0000 +#define MCDE_OVL2CONF_LPF(__x) \ + MCDE_VAL2REG(MCDE_OVL2CONF, LPF, __x) +#define MCDE_OVL3CONF 0x00000464 +#define MCDE_OVL3CONF_PPL_SHIFT 0 +#define MCDE_OVL3CONF_PPL_MASK 0x000007FF +#define MCDE_OVL3CONF_PPL(__x) \ + MCDE_VAL2REG(MCDE_OVL3CONF, PPL, __x) +#define MCDE_OVL3CONF_EXTSRC_ID_SHIFT 11 +#define MCDE_OVL3CONF_EXTSRC_ID_MASK 0x00007800 +#define MCDE_OVL3CONF_EXTSRC_ID(__x) \ + MCDE_VAL2REG(MCDE_OVL3CONF, EXTSRC_ID, __x) +#define MCDE_OVL3CONF_LPF_SHIFT 16 +#define MCDE_OVL3CONF_LPF_MASK 0x07FF0000 +#define MCDE_OVL3CONF_LPF(__x) \ + MCDE_VAL2REG(MCDE_OVL3CONF, LPF, __x) +#define MCDE_OVL4CONF 0x00000484 +#define MCDE_OVL4CONF_PPL_SHIFT 0 +#define MCDE_OVL4CONF_PPL_MASK 0x000007FF +#define MCDE_OVL4CONF_PPL(__x) \ + MCDE_VAL2REG(MCDE_OVL4CONF, PPL, __x) +#define MCDE_OVL4CONF_EXTSRC_ID_SHIFT 11 +#define MCDE_OVL4CONF_EXTSRC_ID_MASK 0x00007800 +#define MCDE_OVL4CONF_EXTSRC_ID(__x) \ + MCDE_VAL2REG(MCDE_OVL4CONF, EXTSRC_ID, __x) +#define MCDE_OVL4CONF_LPF_SHIFT 16 +#define MCDE_OVL4CONF_LPF_MASK 0x07FF0000 +#define MCDE_OVL4CONF_LPF(__x) \ + MCDE_VAL2REG(MCDE_OVL4CONF, LPF, __x) +#define MCDE_OVL5CONF 0x000004A4 +#define MCDE_OVL5CONF_PPL_SHIFT 0 +#define MCDE_OVL5CONF_PPL_MASK 0x000007FF +#define MCDE_OVL5CONF_PPL(__x) \ + MCDE_VAL2REG(MCDE_OVL5CONF, PPL, __x) +#define MCDE_OVL5CONF_EXTSRC_ID_SHIFT 11 +#define MCDE_OVL5CONF_EXTSRC_ID_MASK 0x00007800 +#define MCDE_OVL5CONF_EXTSRC_ID(__x) \ + MCDE_VAL2REG(MCDE_OVL5CONF, EXTSRC_ID, __x) +#define MCDE_OVL5CONF_LPF_SHIFT 16 +#define MCDE_OVL5CONF_LPF_MASK 0x07FF0000 +#define MCDE_OVL5CONF_LPF(__x) \ + MCDE_VAL2REG(MCDE_OVL5CONF, LPF, __x) +#define MCDE_OVL0CONF2 0x00000408 +#define MCDE_OVL0CONF2_GROUPOFFSET 0x20 +#define MCDE_OVL0CONF2_BP_SHIFT 0 +#define MCDE_OVL0CONF2_BP_MASK 0x00000001 +#define MCDE_OVL0CONF2_BP_PER_PIXEL_ALPHA 0 +#define MCDE_OVL0CONF2_BP_CONSTANT_ALPHA 1 +#define MCDE_OVL0CONF2_BP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL0CONF2, BP, MCDE_OVL0CONF2_BP_##__x) +#define MCDE_OVL0CONF2_BP(__x) \ + MCDE_VAL2REG(MCDE_OVL0CONF2, BP, __x) +#define MCDE_OVL0CONF2_ALPHAVALUE_SHIFT 1 +#define MCDE_OVL0CONF2_ALPHAVALUE_MASK 0x000001FE +#define MCDE_OVL0CONF2_ALPHAVALUE(__x) \ + MCDE_VAL2REG(MCDE_OVL0CONF2, ALPHAVALUE, __x) +#define MCDE_OVL0CONF2_OPQ_SHIFT 9 +#define MCDE_OVL0CONF2_OPQ_MASK 0x00000200 +#define MCDE_OVL0CONF2_OPQ(__x) \ + MCDE_VAL2REG(MCDE_OVL0CONF2, OPQ, __x) +#define MCDE_OVL0CONF2_PIXOFF_SHIFT 10 +#define MCDE_OVL0CONF2_PIXOFF_MASK 0x0000FC00 +#define MCDE_OVL0CONF2_PIXOFF(__x) \ + MCDE_VAL2REG(MCDE_OVL0CONF2, PIXOFF, __x) +#define MCDE_OVL0CONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT 16 +#define MCDE_OVL0CONF2_PIXELFETCHERWATERMARKLEVEL_MASK 0x1FFF0000 +#define MCDE_OVL0CONF2_PIXELFETCHERWATERMARKLEVEL(__x) \ + MCDE_VAL2REG(MCDE_OVL0CONF2, PIXELFETCHERWATERMARKLEVEL, __x) +#define MCDE_OVL1CONF2 0x00000428 +#define MCDE_OVL1CONF2_BP_SHIFT 0 +#define MCDE_OVL1CONF2_BP_MASK 0x00000001 +#define MCDE_OVL1CONF2_BP_PER_PIXEL_ALPHA 0 +#define MCDE_OVL1CONF2_BP_CONSTANT_ALPHA 1 +#define MCDE_OVL1CONF2_BP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL1CONF2, BP, MCDE_OVL1CONF2_BP_##__x) +#define MCDE_OVL1CONF2_BP(__x) \ + MCDE_VAL2REG(MCDE_OVL1CONF2, BP, __x) +#define MCDE_OVL1CONF2_ALPHAVALUE_SHIFT 1 +#define MCDE_OVL1CONF2_ALPHAVALUE_MASK 0x000001FE +#define MCDE_OVL1CONF2_ALPHAVALUE(__x) \ + MCDE_VAL2REG(MCDE_OVL1CONF2, ALPHAVALUE, __x) +#define MCDE_OVL1CONF2_OPQ_SHIFT 9 +#define MCDE_OVL1CONF2_OPQ_MASK 0x00000200 +#define MCDE_OVL1CONF2_OPQ(__x) \ + MCDE_VAL2REG(MCDE_OVL1CONF2, OPQ, __x) +#define MCDE_OVL1CONF2_PIXOFF_SHIFT 10 +#define MCDE_OVL1CONF2_PIXOFF_MASK 0x0000FC00 +#define MCDE_OVL1CONF2_PIXOFF(__x) \ + MCDE_VAL2REG(MCDE_OVL1CONF2, PIXOFF, __x) +#define MCDE_OVL1CONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT 16 +#define MCDE_OVL1CONF2_PIXELFETCHERWATERMARKLEVEL_MASK 0x1FFF0000 +#define MCDE_OVL1CONF2_PIXELFETCHERWATERMARKLEVEL(__x) \ + MCDE_VAL2REG(MCDE_OVL1CONF2, PIXELFETCHERWATERMARKLEVEL, __x) +#define MCDE_OVL2CONF2 0x00000448 +#define MCDE_OVL2CONF2_BP_SHIFT 0 +#define MCDE_OVL2CONF2_BP_MASK 0x00000001 +#define MCDE_OVL2CONF2_BP_PER_PIXEL_ALPHA 0 +#define MCDE_OVL2CONF2_BP_CONSTANT_ALPHA 1 +#define MCDE_OVL2CONF2_BP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL2CONF2, BP, MCDE_OVL2CONF2_BP_##__x) +#define MCDE_OVL2CONF2_BP(__x) \ + MCDE_VAL2REG(MCDE_OVL2CONF2, BP, __x) +#define MCDE_OVL2CONF2_ALPHAVALUE_SHIFT 1 +#define MCDE_OVL2CONF2_ALPHAVALUE_MASK 0x000001FE +#define MCDE_OVL2CONF2_ALPHAVALUE(__x) \ + MCDE_VAL2REG(MCDE_OVL2CONF2, ALPHAVALUE, __x) +#define MCDE_OVL2CONF2_OPQ_SHIFT 9 +#define MCDE_OVL2CONF2_OPQ_MASK 0x00000200 +#define MCDE_OVL2CONF2_OPQ(__x) \ + MCDE_VAL2REG(MCDE_OVL2CONF2, OPQ, __x) +#define MCDE_OVL2CONF2_PIXOFF_SHIFT 10 +#define MCDE_OVL2CONF2_PIXOFF_MASK 0x0000FC00 +#define MCDE_OVL2CONF2_PIXOFF(__x) \ + MCDE_VAL2REG(MCDE_OVL2CONF2, PIXOFF, __x) +#define MCDE_OVL2CONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT 16 +#define MCDE_OVL2CONF2_PIXELFETCHERWATERMARKLEVEL_MASK 0x1FFF0000 +#define MCDE_OVL2CONF2_PIXELFETCHERWATERMARKLEVEL(__x) \ + MCDE_VAL2REG(MCDE_OVL2CONF2, PIXELFETCHERWATERMARKLEVEL, __x) +#define MCDE_OVL3CONF2 0x00000468 +#define MCDE_OVL3CONF2_BP_SHIFT 0 +#define MCDE_OVL3CONF2_BP_MASK 0x00000001 +#define MCDE_OVL3CONF2_BP_PER_PIXEL_ALPHA 0 +#define MCDE_OVL3CONF2_BP_CONSTANT_ALPHA 1 +#define MCDE_OVL3CONF2_BP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL3CONF2, BP, MCDE_OVL3CONF2_BP_##__x) +#define MCDE_OVL3CONF2_BP(__x) \ + MCDE_VAL2REG(MCDE_OVL3CONF2, BP, __x) +#define MCDE_OVL3CONF2_ALPHAVALUE_SHIFT 1 +#define MCDE_OVL3CONF2_ALPHAVALUE_MASK 0x000001FE +#define MCDE_OVL3CONF2_ALPHAVALUE(__x) \ + MCDE_VAL2REG(MCDE_OVL3CONF2, ALPHAVALUE, __x) +#define MCDE_OVL3CONF2_OPQ_SHIFT 9 +#define MCDE_OVL3CONF2_OPQ_MASK 0x00000200 +#define MCDE_OVL3CONF2_OPQ(__x) \ + MCDE_VAL2REG(MCDE_OVL3CONF2, OPQ, __x) +#define MCDE_OVL3CONF2_PIXOFF_SHIFT 10 +#define MCDE_OVL3CONF2_PIXOFF_MASK 0x0000FC00 +#define MCDE_OVL3CONF2_PIXOFF(__x) \ + MCDE_VAL2REG(MCDE_OVL3CONF2, PIXOFF, __x) +#define MCDE_OVL3CONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT 16 +#define MCDE_OVL3CONF2_PIXELFETCHERWATERMARKLEVEL_MASK 0x1FFF0000 +#define MCDE_OVL3CONF2_PIXELFETCHERWATERMARKLEVEL(__x) \ + MCDE_VAL2REG(MCDE_OVL3CONF2, PIXELFETCHERWATERMARKLEVEL, __x) +#define MCDE_OVL4CONF2 0x00000488 +#define MCDE_OVL4CONF2_BP_SHIFT 0 +#define MCDE_OVL4CONF2_BP_MASK 0x00000001 +#define MCDE_OVL4CONF2_BP_PER_PIXEL_ALPHA 0 +#define MCDE_OVL4CONF2_BP_CONSTANT_ALPHA 1 +#define MCDE_OVL4CONF2_BP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL4CONF2, BP, MCDE_OVL4CONF2_BP_##__x) +#define MCDE_OVL4CONF2_BP(__x) \ + MCDE_VAL2REG(MCDE_OVL4CONF2, BP, __x) +#define MCDE_OVL4CONF2_ALPHAVALUE_SHIFT 1 +#define MCDE_OVL4CONF2_ALPHAVALUE_MASK 0x000001FE +#define MCDE_OVL4CONF2_ALPHAVALUE(__x) \ + MCDE_VAL2REG(MCDE_OVL4CONF2, ALPHAVALUE, __x) +#define MCDE_OVL4CONF2_OPQ_SHIFT 9 +#define MCDE_OVL4CONF2_OPQ_MASK 0x00000200 +#define MCDE_OVL4CONF2_OPQ(__x) \ + MCDE_VAL2REG(MCDE_OVL4CONF2, OPQ, __x) +#define MCDE_OVL4CONF2_PIXOFF_SHIFT 10 +#define MCDE_OVL4CONF2_PIXOFF_MASK 0x0000FC00 +#define MCDE_OVL4CONF2_PIXOFF(__x) \ + MCDE_VAL2REG(MCDE_OVL4CONF2, PIXOFF, __x) +#define MCDE_OVL4CONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT 16 +#define MCDE_OVL4CONF2_PIXELFETCHERWATERMARKLEVEL_MASK 0x1FFF0000 +#define MCDE_OVL4CONF2_PIXELFETCHERWATERMARKLEVEL(__x) \ + MCDE_VAL2REG(MCDE_OVL4CONF2, PIXELFETCHERWATERMARKLEVEL, __x) +#define MCDE_OVL5CONF2 0x000004A8 +#define MCDE_OVL5CONF2_BP_SHIFT 0 +#define MCDE_OVL5CONF2_BP_MASK 0x00000001 +#define MCDE_OVL5CONF2_BP_PER_PIXEL_ALPHA 0 +#define MCDE_OVL5CONF2_BP_CONSTANT_ALPHA 1 +#define MCDE_OVL5CONF2_BP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_OVL5CONF2, BP, MCDE_OVL5CONF2_BP_##__x) +#define MCDE_OVL5CONF2_BP(__x) \ + MCDE_VAL2REG(MCDE_OVL5CONF2, BP, __x) +#define MCDE_OVL5CONF2_ALPHAVALUE_SHIFT 1 +#define MCDE_OVL5CONF2_ALPHAVALUE_MASK 0x000001FE +#define MCDE_OVL5CONF2_ALPHAVALUE(__x) \ + MCDE_VAL2REG(MCDE_OVL5CONF2, ALPHAVALUE, __x) +#define MCDE_OVL5CONF2_OPQ_SHIFT 9 +#define MCDE_OVL5CONF2_OPQ_MASK 0x00000200 +#define MCDE_OVL5CONF2_OPQ(__x) \ + MCDE_VAL2REG(MCDE_OVL5CONF2, OPQ, __x) +#define MCDE_OVL5CONF2_PIXOFF_SHIFT 10 +#define MCDE_OVL5CONF2_PIXOFF_MASK 0x0000FC00 +#define MCDE_OVL5CONF2_PIXOFF(__x) \ + MCDE_VAL2REG(MCDE_OVL5CONF2, PIXOFF, __x) +#define MCDE_OVL5CONF2_PIXELFETCHERWATERMARKLEVEL_SHIFT 16 +#define MCDE_OVL5CONF2_PIXELFETCHERWATERMARKLEVEL_MASK 0x1FFF0000 +#define MCDE_OVL5CONF2_PIXELFETCHERWATERMARKLEVEL(__x) \ + MCDE_VAL2REG(MCDE_OVL5CONF2, PIXELFETCHERWATERMARKLEVEL, __x) +#define MCDE_OVL0LJINC 0x0000040C +#define MCDE_OVL0LJINC_GROUPOFFSET 0x20 +#define MCDE_OVL0LJINC_LJINC_SHIFT 0 +#define MCDE_OVL0LJINC_LJINC_MASK 0xFFFFFFFF +#define MCDE_OVL0LJINC_LJINC(__x) \ + MCDE_VAL2REG(MCDE_OVL0LJINC, LJINC, __x) +#define MCDE_OVL1LJINC 0x0000042C +#define MCDE_OVL1LJINC_LJINC_SHIFT 0 +#define MCDE_OVL1LJINC_LJINC_MASK 0xFFFFFFFF +#define MCDE_OVL1LJINC_LJINC(__x) \ + MCDE_VAL2REG(MCDE_OVL1LJINC, LJINC, __x) +#define MCDE_OVL2LJINC 0x0000044C +#define MCDE_OVL2LJINC_LJINC_SHIFT 0 +#define MCDE_OVL2LJINC_LJINC_MASK 0xFFFFFFFF +#define MCDE_OVL2LJINC_LJINC(__x) \ + MCDE_VAL2REG(MCDE_OVL2LJINC, LJINC, __x) +#define MCDE_OVL3LJINC 0x0000046C +#define MCDE_OVL3LJINC_LJINC_SHIFT 0 +#define MCDE_OVL3LJINC_LJINC_MASK 0xFFFFFFFF +#define MCDE_OVL3LJINC_LJINC(__x) \ + MCDE_VAL2REG(MCDE_OVL3LJINC, LJINC, __x) +#define MCDE_OVL4LJINC 0x0000048C +#define MCDE_OVL4LJINC_LJINC_SHIFT 0 +#define MCDE_OVL4LJINC_LJINC_MASK 0xFFFFFFFF +#define MCDE_OVL4LJINC_LJINC(__x) \ + MCDE_VAL2REG(MCDE_OVL4LJINC, LJINC, __x) +#define MCDE_OVL5LJINC 0x000004AC +#define MCDE_OVL5LJINC_LJINC_SHIFT 0 +#define MCDE_OVL5LJINC_LJINC_MASK 0xFFFFFFFF +#define MCDE_OVL5LJINC_LJINC(__x) \ + MCDE_VAL2REG(MCDE_OVL5LJINC, LJINC, __x) +#define MCDE_OVL0CROP 0x00000410 +#define MCDE_OVL0CROP_GROUPOFFSET 0x20 +#define MCDE_OVL0CROP_TMRGN_SHIFT 0 +#define MCDE_OVL0CROP_TMRGN_MASK 0x003FFFFF +#define MCDE_OVL0CROP_TMRGN(__x) \ + MCDE_VAL2REG(MCDE_OVL0CROP, TMRGN, __x) +#define MCDE_OVL0CROP_LMRGN_SHIFT 22 +#define MCDE_OVL0CROP_LMRGN_MASK 0xFFC00000 +#define MCDE_OVL0CROP_LMRGN(__x) \ + MCDE_VAL2REG(MCDE_OVL0CROP, LMRGN, __x) +#define MCDE_OVL1CROP 0x00000430 +#define MCDE_OVL1CROP_TMRGN_SHIFT 0 +#define MCDE_OVL1CROP_TMRGN_MASK 0x003FFFFF +#define MCDE_OVL1CROP_TMRGN(__x) \ + MCDE_VAL2REG(MCDE_OVL1CROP, TMRGN, __x) +#define MCDE_OVL1CROP_LMRGN_SHIFT 22 +#define MCDE_OVL1CROP_LMRGN_MASK 0xFFC00000 +#define MCDE_OVL1CROP_LMRGN(__x) \ + MCDE_VAL2REG(MCDE_OVL1CROP, LMRGN, __x) +#define MCDE_OVL2CROP 0x00000450 +#define MCDE_OVL2CROP_TMRGN_SHIFT 0 +#define MCDE_OVL2CROP_TMRGN_MASK 0x003FFFFF +#define MCDE_OVL2CROP_TMRGN(__x) \ + MCDE_VAL2REG(MCDE_OVL2CROP, TMRGN, __x) +#define MCDE_OVL2CROP_LMRGN_SHIFT 22 +#define MCDE_OVL2CROP_LMRGN_MASK 0xFFC00000 +#define MCDE_OVL2CROP_LMRGN(__x) \ + MCDE_VAL2REG(MCDE_OVL2CROP, LMRGN, __x) +#define MCDE_OVL3CROP 0x00000470 +#define MCDE_OVL3CROP_TMRGN_SHIFT 0 +#define MCDE_OVL3CROP_TMRGN_MASK 0x003FFFFF +#define MCDE_OVL3CROP_TMRGN(__x) \ + MCDE_VAL2REG(MCDE_OVL3CROP, TMRGN, __x) +#define MCDE_OVL3CROP_LMRGN_SHIFT 22 +#define MCDE_OVL3CROP_LMRGN_MASK 0xFFC00000 +#define MCDE_OVL3CROP_LMRGN(__x) \ + MCDE_VAL2REG(MCDE_OVL3CROP, LMRGN, __x) +#define MCDE_OVL4CROP 0x00000490 +#define MCDE_OVL4CROP_TMRGN_SHIFT 0 +#define MCDE_OVL4CROP_TMRGN_MASK 0x003FFFFF +#define MCDE_OVL4CROP_TMRGN(__x) \ + MCDE_VAL2REG(MCDE_OVL4CROP, TMRGN, __x) +#define MCDE_OVL4CROP_LMRGN_SHIFT 22 +#define MCDE_OVL4CROP_LMRGN_MASK 0xFFC00000 +#define MCDE_OVL4CROP_LMRGN(__x) \ + MCDE_VAL2REG(MCDE_OVL4CROP, LMRGN, __x) +#define MCDE_OVL5CROP 0x000004B0 +#define MCDE_OVL5CROP_TMRGN_SHIFT 0 +#define MCDE_OVL5CROP_TMRGN_MASK 0x003FFFFF +#define MCDE_OVL5CROP_TMRGN(__x) \ + MCDE_VAL2REG(MCDE_OVL5CROP, TMRGN, __x) +#define MCDE_OVL5CROP_LMRGN_SHIFT 22 +#define MCDE_OVL5CROP_LMRGN_MASK 0xFFC00000 +#define MCDE_OVL5CROP_LMRGN(__x) \ + MCDE_VAL2REG(MCDE_OVL5CROP, LMRGN, __x) +#define MCDE_OVL0COMP 0x00000414 +#define MCDE_OVL0COMP_GROUPOFFSET 0x20 +#define MCDE_OVL0COMP_XPOS_SHIFT 0 +#define MCDE_OVL0COMP_XPOS_MASK 0x000007FF +#define MCDE_OVL0COMP_XPOS(__x) \ + MCDE_VAL2REG(MCDE_OVL0COMP, XPOS, __x) +#define MCDE_OVL0COMP_CH_ID_SHIFT 11 +#define MCDE_OVL0COMP_CH_ID_MASK 0x00007800 +#define MCDE_OVL0COMP_CH_ID(__x) \ + MCDE_VAL2REG(MCDE_OVL0COMP, CH_ID, __x) +#define MCDE_OVL0COMP_YPOS_SHIFT 16 +#define MCDE_OVL0COMP_YPOS_MASK 0x07FF0000 +#define MCDE_OVL0COMP_YPOS(__x) \ + MCDE_VAL2REG(MCDE_OVL0COMP, YPOS, __x) +#define MCDE_OVL0COMP_Z_SHIFT 27 +#define MCDE_OVL0COMP_Z_MASK 0x78000000 +#define MCDE_OVL0COMP_Z(__x) \ + MCDE_VAL2REG(MCDE_OVL0COMP, Z, __x) +#define MCDE_OVL1COMP 0x00000434 +#define MCDE_OVL1COMP_XPOS_SHIFT 0 +#define MCDE_OVL1COMP_XPOS_MASK 0x000007FF +#define MCDE_OVL1COMP_XPOS(__x) \ + MCDE_VAL2REG(MCDE_OVL1COMP, XPOS, __x) +#define MCDE_OVL1COMP_CH_ID_SHIFT 11 +#define MCDE_OVL1COMP_CH_ID_MASK 0x00007800 +#define MCDE_OVL1COMP_CH_ID(__x) \ + MCDE_VAL2REG(MCDE_OVL1COMP, CH_ID, __x) +#define MCDE_OVL1COMP_YPOS_SHIFT 16 +#define MCDE_OVL1COMP_YPOS_MASK 0x07FF0000 +#define MCDE_OVL1COMP_YPOS(__x) \ + MCDE_VAL2REG(MCDE_OVL1COMP, YPOS, __x) +#define MCDE_OVL1COMP_Z_SHIFT 27 +#define MCDE_OVL1COMP_Z_MASK 0x78000000 +#define MCDE_OVL1COMP_Z(__x) \ + MCDE_VAL2REG(MCDE_OVL1COMP, Z, __x) +#define MCDE_OVL2COMP 0x00000454 +#define MCDE_OVL2COMP_XPOS_SHIFT 0 +#define MCDE_OVL2COMP_XPOS_MASK 0x000007FF +#define MCDE_OVL2COMP_XPOS(__x) \ + MCDE_VAL2REG(MCDE_OVL2COMP, XPOS, __x) +#define MCDE_OVL2COMP_CH_ID_SHIFT 11 +#define MCDE_OVL2COMP_CH_ID_MASK 0x00007800 +#define MCDE_OVL2COMP_CH_ID(__x) \ + MCDE_VAL2REG(MCDE_OVL2COMP, CH_ID, __x) +#define MCDE_OVL2COMP_YPOS_SHIFT 16 +#define MCDE_OVL2COMP_YPOS_MASK 0x07FF0000 +#define MCDE_OVL2COMP_YPOS(__x) \ + MCDE_VAL2REG(MCDE_OVL2COMP, YPOS, __x) +#define MCDE_OVL2COMP_Z_SHIFT 27 +#define MCDE_OVL2COMP_Z_MASK 0x78000000 +#define MCDE_OVL2COMP_Z(__x) \ + MCDE_VAL2REG(MCDE_OVL2COMP, Z, __x) +#define MCDE_OVL3COMP 0x00000474 +#define MCDE_OVL3COMP_XPOS_SHIFT 0 +#define MCDE_OVL3COMP_XPOS_MASK 0x000007FF +#define MCDE_OVL3COMP_XPOS(__x) \ + MCDE_VAL2REG(MCDE_OVL3COMP, XPOS, __x) +#define MCDE_OVL3COMP_CH_ID_SHIFT 11 +#define MCDE_OVL3COMP_CH_ID_MASK 0x00007800 +#define MCDE_OVL3COMP_CH_ID(__x) \ + MCDE_VAL2REG(MCDE_OVL3COMP, CH_ID, __x) +#define MCDE_OVL3COMP_YPOS_SHIFT 16 +#define MCDE_OVL3COMP_YPOS_MASK 0x07FF0000 +#define MCDE_OVL3COMP_YPOS(__x) \ + MCDE_VAL2REG(MCDE_OVL3COMP, YPOS, __x) +#define MCDE_OVL3COMP_Z_SHIFT 27 +#define MCDE_OVL3COMP_Z_MASK 0x78000000 +#define MCDE_OVL3COMP_Z(__x) \ + MCDE_VAL2REG(MCDE_OVL3COMP, Z, __x) +#define MCDE_OVL4COMP 0x00000494 +#define MCDE_OVL4COMP_XPOS_SHIFT 0 +#define MCDE_OVL4COMP_XPOS_MASK 0x000007FF +#define MCDE_OVL4COMP_XPOS(__x) \ + MCDE_VAL2REG(MCDE_OVL4COMP, XPOS, __x) +#define MCDE_OVL4COMP_CH_ID_SHIFT 11 +#define MCDE_OVL4COMP_CH_ID_MASK 0x00007800 +#define MCDE_OVL4COMP_CH_ID(__x) \ + MCDE_VAL2REG(MCDE_OVL4COMP, CH_ID, __x) +#define MCDE_OVL4COMP_YPOS_SHIFT 16 +#define MCDE_OVL4COMP_YPOS_MASK 0x07FF0000 +#define MCDE_OVL4COMP_YPOS(__x) \ + MCDE_VAL2REG(MCDE_OVL4COMP, YPOS, __x) +#define MCDE_OVL4COMP_Z_SHIFT 27 +#define MCDE_OVL4COMP_Z_MASK 0x78000000 +#define MCDE_OVL4COMP_Z(__x) \ + MCDE_VAL2REG(MCDE_OVL4COMP, Z, __x) +#define MCDE_OVL5COMP 0x000004B4 +#define MCDE_OVL5COMP_XPOS_SHIFT 0 +#define MCDE_OVL5COMP_XPOS_MASK 0x000007FF +#define MCDE_OVL5COMP_XPOS(__x) \ + MCDE_VAL2REG(MCDE_OVL5COMP, XPOS, __x) +#define MCDE_OVL5COMP_CH_ID_SHIFT 11 +#define MCDE_OVL5COMP_CH_ID_MASK 0x00007800 +#define MCDE_OVL5COMP_CH_ID(__x) \ + MCDE_VAL2REG(MCDE_OVL5COMP, CH_ID, __x) +#define MCDE_OVL5COMP_YPOS_SHIFT 16 +#define MCDE_OVL5COMP_YPOS_MASK 0x07FF0000 +#define MCDE_OVL5COMP_YPOS(__x) \ + MCDE_VAL2REG(MCDE_OVL5COMP, YPOS, __x) +#define MCDE_OVL5COMP_Z_SHIFT 27 +#define MCDE_OVL5COMP_Z_MASK 0x78000000 +#define MCDE_OVL5COMP_Z(__x) \ + MCDE_VAL2REG(MCDE_OVL5COMP, Z, __x) +#define MCDE_CHNL0CONF 0x00000600 +#define MCDE_CHNL0CONF_GROUPOFFSET 0x20 +#define MCDE_CHNL0CONF_PPL_SHIFT 0 +#define MCDE_CHNL0CONF_PPL_MASK 0x000007FF +#define MCDE_CHNL0CONF_PPL(__x) \ + MCDE_VAL2REG(MCDE_CHNL0CONF, PPL, __x) +#define MCDE_CHNL0CONF_LPF_SHIFT 16 +#define MCDE_CHNL0CONF_LPF_MASK 0x07FF0000 +#define MCDE_CHNL0CONF_LPF(__x) \ + MCDE_VAL2REG(MCDE_CHNL0CONF, LPF, __x) +#define MCDE_CHNL1CONF 0x00000620 +#define MCDE_CHNL1CONF_PPL_SHIFT 0 +#define MCDE_CHNL1CONF_PPL_MASK 0x000007FF +#define MCDE_CHNL1CONF_PPL(__x) \ + MCDE_VAL2REG(MCDE_CHNL1CONF, PPL, __x) +#define MCDE_CHNL1CONF_LPF_SHIFT 16 +#define MCDE_CHNL1CONF_LPF_MASK 0x07FF0000 +#define MCDE_CHNL1CONF_LPF(__x) \ + MCDE_VAL2REG(MCDE_CHNL1CONF, LPF, __x) +#define MCDE_CHNL2CONF 0x00000640 +#define MCDE_CHNL2CONF_PPL_SHIFT 0 +#define MCDE_CHNL2CONF_PPL_MASK 0x000007FF +#define MCDE_CHNL2CONF_PPL(__x) \ + MCDE_VAL2REG(MCDE_CHNL2CONF, PPL, __x) +#define MCDE_CHNL2CONF_LPF_SHIFT 16 +#define MCDE_CHNL2CONF_LPF_MASK 0x07FF0000 +#define MCDE_CHNL2CONF_LPF(__x) \ + MCDE_VAL2REG(MCDE_CHNL2CONF, LPF, __x) +#define MCDE_CHNL3CONF 0x00000660 +#define MCDE_CHNL3CONF_PPL_SHIFT 0 +#define MCDE_CHNL3CONF_PPL_MASK 0x000007FF +#define MCDE_CHNL3CONF_PPL(__x) \ + MCDE_VAL2REG(MCDE_CHNL3CONF, PPL, __x) +#define MCDE_CHNL3CONF_LPF_SHIFT 16 +#define MCDE_CHNL3CONF_LPF_MASK 0x07FF0000 +#define MCDE_CHNL3CONF_LPF(__x) \ + MCDE_VAL2REG(MCDE_CHNL3CONF, LPF, __x) +#define MCDE_CHNL0STAT 0x00000604 +#define MCDE_CHNL0STAT_GROUPOFFSET 0x20 +#define MCDE_CHNL0STAT_CHNLRD_SHIFT 0 +#define MCDE_CHNL0STAT_CHNLRD_MASK 0x00000001 +#define MCDE_CHNL0STAT_CHNLRD(__x) \ + MCDE_VAL2REG(MCDE_CHNL0STAT, CHNLRD, __x) +#define MCDE_CHNL0STAT_CHNLA_SHIFT 1 +#define MCDE_CHNL0STAT_CHNLA_MASK 0x00000002 +#define MCDE_CHNL0STAT_CHNLA(__x) \ + MCDE_VAL2REG(MCDE_CHNL0STAT, CHNLA, __x) +#define MCDE_CHNL0STAT_CHNLBLBCKGND_EN_SHIFT 16 +#define MCDE_CHNL0STAT_CHNLBLBCKGND_EN_MASK 0x00010000 +#define MCDE_CHNL0STAT_CHNLBLBCKGND_EN(__x) \ + MCDE_VAL2REG(MCDE_CHNL0STAT, CHNLBLBCKGND_EN, __x) +#define MCDE_CHNL1STAT 0x00000624 +#define MCDE_CHNL1STAT_CHNLRD_SHIFT 0 +#define MCDE_CHNL1STAT_CHNLRD_MASK 0x00000001 +#define MCDE_CHNL1STAT_CHNLRD(__x) \ + MCDE_VAL2REG(MCDE_CHNL1STAT, CHNLRD, __x) +#define MCDE_CHNL1STAT_CHNLA_SHIFT 1 +#define MCDE_CHNL1STAT_CHNLA_MASK 0x00000002 +#define MCDE_CHNL1STAT_CHNLA(__x) \ + MCDE_VAL2REG(MCDE_CHNL1STAT, CHNLA, __x) +#define MCDE_CHNL1STAT_CHNLBLBCKGND_EN_SHIFT 16 +#define MCDE_CHNL1STAT_CHNLBLBCKGND_EN_MASK 0x00010000 +#define MCDE_CHNL1STAT_CHNLBLBCKGND_EN(__x) \ + MCDE_VAL2REG(MCDE_CHNL1STAT, CHNLBLBCKGND_EN, __x) +#define MCDE_CHNL2STAT 0x00000644 +#define MCDE_CHNL2STAT_CHNLRD_SHIFT 0 +#define MCDE_CHNL2STAT_CHNLRD_MASK 0x00000001 +#define MCDE_CHNL2STAT_CHNLRD(__x) \ + MCDE_VAL2REG(MCDE_CHNL2STAT, CHNLRD, __x) +#define MCDE_CHNL2STAT_CHNLA_SHIFT 1 +#define MCDE_CHNL2STAT_CHNLA_MASK 0x00000002 +#define MCDE_CHNL2STAT_CHNLA(__x) \ + MCDE_VAL2REG(MCDE_CHNL2STAT, CHNLA, __x) +#define MCDE_CHNL2STAT_CHNLBLBCKGND_EN_SHIFT 16 +#define MCDE_CHNL2STAT_CHNLBLBCKGND_EN_MASK 0x00010000 +#define MCDE_CHNL2STAT_CHNLBLBCKGND_EN(__x) \ + MCDE_VAL2REG(MCDE_CHNL2STAT, CHNLBLBCKGND_EN, __x) +#define MCDE_CHNL3STAT 0x00000664 +#define MCDE_CHNL3STAT_CHNLRD_SHIFT 0 +#define MCDE_CHNL3STAT_CHNLRD_MASK 0x00000001 +#define MCDE_CHNL3STAT_CHNLRD(__x) \ + MCDE_VAL2REG(MCDE_CHNL3STAT, CHNLRD, __x) +#define MCDE_CHNL3STAT_CHNLA_SHIFT 1 +#define MCDE_CHNL3STAT_CHNLA_MASK 0x00000002 +#define MCDE_CHNL3STAT_CHNLA(__x) \ + MCDE_VAL2REG(MCDE_CHNL3STAT, CHNLA, __x) +#define MCDE_CHNL3STAT_CHNLBLBCKGND_EN_SHIFT 16 +#define MCDE_CHNL3STAT_CHNLBLBCKGND_EN_MASK 0x00010000 +#define MCDE_CHNL3STAT_CHNLBLBCKGND_EN(__x) \ + MCDE_VAL2REG(MCDE_CHNL3STAT, CHNLBLBCKGND_EN, __x) +#define MCDE_CHNL0SYNCHMOD 0x00000608 +#define MCDE_CHNL0SYNCHMOD_GROUPOFFSET 0x20 +#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SHIFT 0 +#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH_MASK 0x00000003 +#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE 0 +#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH_NO_SYNCH 1 +#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE 2 +#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CHNL0SYNCHMOD, SRC_SYNCH, \ + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_##__x) +#define MCDE_CHNL0SYNCHMOD_SRC_SYNCH(__x) \ + MCDE_VAL2REG(MCDE_CHNL0SYNCHMOD, SRC_SYNCH, __x) +#define MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_SHIFT 2 +#define MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_MASK 0x0000001C +#define MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_FORMATTER 0 +#define MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_TE0 1 +#define MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_TE1 2 +#define MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CHNL0SYNCHMOD, OUT_SYNCH_SRC, \ + MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_##__x) +#define MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC(__x) \ + MCDE_VAL2REG(MCDE_CHNL0SYNCHMOD, OUT_SYNCH_SRC, __x) +#define MCDE_CHNL1SYNCHMOD 0x00000628 +#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH_SHIFT 0 +#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH_MASK 0x00000003 +#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH_HARDWARE 0 +#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH_NO_SYNCH 1 +#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH_SOFTWARE 2 +#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CHNL1SYNCHMOD, SRC_SYNCH, \ + MCDE_CHNL1SYNCHMOD_SRC_SYNCH_##__x) +#define MCDE_CHNL1SYNCHMOD_SRC_SYNCH(__x) \ + MCDE_VAL2REG(MCDE_CHNL1SYNCHMOD, SRC_SYNCH, __x) +#define MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC_SHIFT 2 +#define MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC_MASK 0x0000001C +#define MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC_FORMATTER 0 +#define MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC_TE0 1 +#define MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC_TE1 2 +#define MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CHNL1SYNCHMOD, OUT_SYNCH_SRC, \ + MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC_##__x) +#define MCDE_CHNL1SYNCHMOD_OUT_SYNCH_SRC(__x) \ + MCDE_VAL2REG(MCDE_CHNL1SYNCHMOD, OUT_SYNCH_SRC, __x) +#define MCDE_CHNL2SYNCHMOD 0x00000648 +#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH_SHIFT 0 +#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH_MASK 0x00000003 +#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH_HARDWARE 0 +#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH_NO_SYNCH 1 +#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH_SOFTWARE 2 +#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CHNL2SYNCHMOD, SRC_SYNCH, \ + MCDE_CHNL2SYNCHMOD_SRC_SYNCH_##__x) +#define MCDE_CHNL2SYNCHMOD_SRC_SYNCH(__x) \ + MCDE_VAL2REG(MCDE_CHNL2SYNCHMOD, SRC_SYNCH, __x) +#define MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC_SHIFT 2 +#define MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC_MASK 0x0000001C +#define MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC_FORMATTER 0 +#define MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC_TE0 1 +#define MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC_TE1 2 +#define MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CHNL2SYNCHMOD, OUT_SYNCH_SRC, \ + MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC_##__x) +#define MCDE_CHNL2SYNCHMOD_OUT_SYNCH_SRC(__x) \ + MCDE_VAL2REG(MCDE_CHNL2SYNCHMOD, OUT_SYNCH_SRC, __x) +#define MCDE_CHNL3SYNCHMOD 0x00000668 +#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH_SHIFT 0 +#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH_MASK 0x00000003 +#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH_HARDWARE 0 +#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH_NO_SYNCH 1 +#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH_SOFTWARE 2 +#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CHNL3SYNCHMOD, SRC_SYNCH, \ + MCDE_CHNL3SYNCHMOD_SRC_SYNCH_##__x) +#define MCDE_CHNL3SYNCHMOD_SRC_SYNCH(__x) \ + MCDE_VAL2REG(MCDE_CHNL3SYNCHMOD, SRC_SYNCH, __x) +#define MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC_SHIFT 2 +#define MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC_MASK 0x0000001C +#define MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC_FORMATTER 0 +#define MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC_TE0 1 +#define MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC_TE1 2 +#define MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CHNL3SYNCHMOD, OUT_SYNCH_SRC, \ + MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC_##__x) +#define MCDE_CHNL3SYNCHMOD_OUT_SYNCH_SRC(__x) \ + MCDE_VAL2REG(MCDE_CHNL3SYNCHMOD, OUT_SYNCH_SRC, __x) +#define MCDE_CHNL0SYNCHSW 0x0000060C +#define MCDE_CHNL0SYNCHSW_GROUPOFFSET 0x20 +#define MCDE_CHNL0SYNCHSW_SW_TRIG_SHIFT 0 +#define MCDE_CHNL0SYNCHSW_SW_TRIG_MASK 0x00000001 +#define MCDE_CHNL0SYNCHSW_SW_TRIG(__x) \ + MCDE_VAL2REG(MCDE_CHNL0SYNCHSW, SW_TRIG, __x) +#define MCDE_CHNL1SYNCHSW 0x0000062C +#define MCDE_CHNL1SYNCHSW_SW_TRIG_SHIFT 0 +#define MCDE_CHNL1SYNCHSW_SW_TRIG_MASK 0x00000001 +#define MCDE_CHNL1SYNCHSW_SW_TRIG(__x) \ + MCDE_VAL2REG(MCDE_CHNL1SYNCHSW, SW_TRIG, __x) +#define MCDE_CHNL2SYNCHSW 0x0000064C +#define MCDE_CHNL2SYNCHSW_SW_TRIG_SHIFT 0 +#define MCDE_CHNL2SYNCHSW_SW_TRIG_MASK 0x00000001 +#define MCDE_CHNL2SYNCHSW_SW_TRIG(__x) \ + MCDE_VAL2REG(MCDE_CHNL2SYNCHSW, SW_TRIG, __x) +#define MCDE_CHNL3SYNCHSW 0x0000066C +#define MCDE_CHNL3SYNCHSW_SW_TRIG_SHIFT 0 +#define MCDE_CHNL3SYNCHSW_SW_TRIG_MASK 0x00000001 +#define MCDE_CHNL3SYNCHSW_SW_TRIG(__x) \ + MCDE_VAL2REG(MCDE_CHNL3SYNCHSW, SW_TRIG, __x) +#define MCDE_CHNL0BCKGNDCOL 0x00000610 +#define MCDE_CHNL0BCKGNDCOL_GROUPOFFSET 0x20 +#define MCDE_CHNL0BCKGNDCOL_B_SHIFT 0 +#define MCDE_CHNL0BCKGNDCOL_B_MASK 0x000000FF +#define MCDE_CHNL0BCKGNDCOL_B(__x) \ + MCDE_VAL2REG(MCDE_CHNL0BCKGNDCOL, B, __x) +#define MCDE_CHNL0BCKGNDCOL_G_SHIFT 8 +#define MCDE_CHNL0BCKGNDCOL_G_MASK 0x0000FF00 +#define MCDE_CHNL0BCKGNDCOL_G(__x) \ + MCDE_VAL2REG(MCDE_CHNL0BCKGNDCOL, G, __x) +#define MCDE_CHNL0BCKGNDCOL_R_SHIFT 16 +#define MCDE_CHNL0BCKGNDCOL_R_MASK 0x00FF0000 +#define MCDE_CHNL0BCKGNDCOL_R(__x) \ + MCDE_VAL2REG(MCDE_CHNL0BCKGNDCOL, R, __x) +#define MCDE_CHNL1BCKGNDCOL 0x00000630 +#define MCDE_CHNL1BCKGNDCOL_B_SHIFT 0 +#define MCDE_CHNL1BCKGNDCOL_B_MASK 0x000000FF +#define MCDE_CHNL1BCKGNDCOL_B(__x) \ + MCDE_VAL2REG(MCDE_CHNL1BCKGNDCOL, B, __x) +#define MCDE_CHNL1BCKGNDCOL_G_SHIFT 8 +#define MCDE_CHNL1BCKGNDCOL_G_MASK 0x0000FF00 +#define MCDE_CHNL1BCKGNDCOL_G(__x) \ + MCDE_VAL2REG(MCDE_CHNL1BCKGNDCOL, G, __x) +#define MCDE_CHNL1BCKGNDCOL_R_SHIFT 16 +#define MCDE_CHNL1BCKGNDCOL_R_MASK 0x00FF0000 +#define MCDE_CHNL1BCKGNDCOL_R(__x) \ + MCDE_VAL2REG(MCDE_CHNL1BCKGNDCOL, R, __x) +#define MCDE_CHNL2BCKGNDCOL 0x00000650 +#define MCDE_CHNL2BCKGNDCOL_B_SHIFT 0 +#define MCDE_CHNL2BCKGNDCOL_B_MASK 0x000000FF +#define MCDE_CHNL2BCKGNDCOL_B(__x) \ + MCDE_VAL2REG(MCDE_CHNL2BCKGNDCOL, B, __x) +#define MCDE_CHNL2BCKGNDCOL_G_SHIFT 8 +#define MCDE_CHNL2BCKGNDCOL_G_MASK 0x0000FF00 +#define MCDE_CHNL2BCKGNDCOL_G(__x) \ + MCDE_VAL2REG(MCDE_CHNL2BCKGNDCOL, G, __x) +#define MCDE_CHNL2BCKGNDCOL_R_SHIFT 16 +#define MCDE_CHNL2BCKGNDCOL_R_MASK 0x00FF0000 +#define MCDE_CHNL2BCKGNDCOL_R(__x) \ + MCDE_VAL2REG(MCDE_CHNL2BCKGNDCOL, R, __x) +#define MCDE_CHNL3BCKGNDCOL 0x00000670 +#define MCDE_CHNL3BCKGNDCOL_B_SHIFT 0 +#define MCDE_CHNL3BCKGNDCOL_B_MASK 0x000000FF +#define MCDE_CHNL3BCKGNDCOL_B(__x) \ + MCDE_VAL2REG(MCDE_CHNL3BCKGNDCOL, B, __x) +#define MCDE_CHNL3BCKGNDCOL_G_SHIFT 8 +#define MCDE_CHNL3BCKGNDCOL_G_MASK 0x0000FF00 +#define MCDE_CHNL3BCKGNDCOL_G(__x) \ + MCDE_VAL2REG(MCDE_CHNL3BCKGNDCOL, G, __x) +#define MCDE_CHNL3BCKGNDCOL_R_SHIFT 16 +#define MCDE_CHNL3BCKGNDCOL_R_MASK 0x00FF0000 +#define MCDE_CHNL3BCKGNDCOL_R(__x) \ + MCDE_VAL2REG(MCDE_CHNL3BCKGNDCOL, R, __x) +#define MCDE_CHNL0MUXING 0x00000614 +#define MCDE_CHNL0MUXING_GROUPOFFSET 0x20 +#define MCDE_CHNL0MUXING_FIFO_ID_SHIFT 0 +#define MCDE_CHNL0MUXING_FIFO_ID_MASK 0x00000007 +#define MCDE_CHNL0MUXING_FIFO_ID_FIFO_A 0 +#define MCDE_CHNL0MUXING_FIFO_ID_FIFO_B 1 +#define MCDE_CHNL0MUXING_FIFO_ID_FIFO_C0 2 +#define MCDE_CHNL0MUXING_FIFO_ID_FIFO_C1 3 +#define MCDE_CHNL0MUXING_FIFO_ID_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CHNL0MUXING, FIFO_ID, MCDE_CHNL0MUXING_FIFO_ID_##__x) +#define MCDE_CHNL0MUXING_FIFO_ID(__x) \ + MCDE_VAL2REG(MCDE_CHNL0MUXING, FIFO_ID, __x) +#define MCDE_CHNL1MUXING 0x00000634 +#define MCDE_CHNL1MUXING_FIFO_ID_SHIFT 0 +#define MCDE_CHNL1MUXING_FIFO_ID_MASK 0x00000007 +#define MCDE_CHNL1MUXING_FIFO_ID_FIFO_A 0 +#define MCDE_CHNL1MUXING_FIFO_ID_FIFO_B 1 +#define MCDE_CHNL1MUXING_FIFO_ID_FIFO_C0 2 +#define MCDE_CHNL1MUXING_FIFO_ID_FIFO_C1 3 +#define MCDE_CHNL1MUXING_FIFO_ID_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CHNL1MUXING, FIFO_ID, MCDE_CHNL1MUXING_FIFO_ID_##__x) +#define MCDE_CHNL1MUXING_FIFO_ID(__x) \ + MCDE_VAL2REG(MCDE_CHNL1MUXING, FIFO_ID, __x) +#define MCDE_CHNL2MUXING 0x00000654 +#define MCDE_CHNL2MUXING_FIFO_ID_SHIFT 0 +#define MCDE_CHNL2MUXING_FIFO_ID_MASK 0x00000007 +#define MCDE_CHNL2MUXING_FIFO_ID_FIFO_A 0 +#define MCDE_CHNL2MUXING_FIFO_ID_FIFO_B 1 +#define MCDE_CHNL2MUXING_FIFO_ID_FIFO_C0 2 +#define MCDE_CHNL2MUXING_FIFO_ID_FIFO_C1 3 +#define MCDE_CHNL2MUXING_FIFO_ID_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CHNL2MUXING, FIFO_ID, MCDE_CHNL2MUXING_FIFO_ID_##__x) +#define MCDE_CHNL2MUXING_FIFO_ID(__x) \ + MCDE_VAL2REG(MCDE_CHNL2MUXING, FIFO_ID, __x) +#define MCDE_CHNL3MUXING 0x00000674 +#define MCDE_CHNL3MUXING_FIFO_ID_SHIFT 0 +#define MCDE_CHNL3MUXING_FIFO_ID_MASK 0x00000007 +#define MCDE_CHNL3MUXING_FIFO_ID_FIFO_A 0 +#define MCDE_CHNL3MUXING_FIFO_ID_FIFO_B 1 +#define MCDE_CHNL3MUXING_FIFO_ID_FIFO_C0 2 +#define MCDE_CHNL3MUXING_FIFO_ID_FIFO_C1 3 +#define MCDE_CHNL3MUXING_FIFO_ID_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CHNL3MUXING, FIFO_ID, MCDE_CHNL3MUXING_FIFO_ID_##__x) +#define MCDE_CHNL3MUXING_FIFO_ID(__x) \ + MCDE_VAL2REG(MCDE_CHNL3MUXING, FIFO_ID, __x) +#define MCDE_CRA0 0x00000800 +#define MCDE_CRA0_GROUPOFFSET 0x200 +#define MCDE_CRA0_FLOEN_SHIFT 0 +#define MCDE_CRA0_FLOEN_MASK 0x00000001 +#define MCDE_CRA0_FLOEN(__x) \ + MCDE_VAL2REG(MCDE_CRA0, FLOEN, __x) +#define MCDE_CRA0_BLENDEN_SHIFT 2 +#define MCDE_CRA0_BLENDEN_MASK 0x00000004 +#define MCDE_CRA0_BLENDEN(__x) \ + MCDE_VAL2REG(MCDE_CRA0, BLENDEN, __x) +#define MCDE_CRA0_AFLICKEN_SHIFT 3 +#define MCDE_CRA0_AFLICKEN_MASK 0x00000008 +#define MCDE_CRA0_AFLICKEN(__x) \ + MCDE_VAL2REG(MCDE_CRA0, AFLICKEN, __x) +#define MCDE_CRA0_PALEN_SHIFT 4 +#define MCDE_CRA0_PALEN_MASK 0x00000010 +#define MCDE_CRA0_PALEN(__x) \ + MCDE_VAL2REG(MCDE_CRA0, PALEN, __x) +#define MCDE_CRA0_DITHEN_SHIFT 5 +#define MCDE_CRA0_DITHEN_MASK 0x00000020 +#define MCDE_CRA0_DITHEN(__x) \ + MCDE_VAL2REG(MCDE_CRA0, DITHEN, __x) +#define MCDE_CRA0_GAMEN_SHIFT 6 +#define MCDE_CRA0_GAMEN_MASK 0x00000040 +#define MCDE_CRA0_GAMEN(__x) \ + MCDE_VAL2REG(MCDE_CRA0, GAMEN, __x) +#define MCDE_CRA0_KEYCTRL_SHIFT 7 +#define MCDE_CRA0_KEYCTRL_MASK 0x00000380 +#define MCDE_CRA0_KEYCTRL_OFF 0 +#define MCDE_CRA0_KEYCTRL_ALPHA_RGB 1 +#define MCDE_CRA0_KEYCTRL_RGB 2 +#define MCDE_CRA0_KEYCTRL_FALPHA_FRGB 4 +#define MCDE_CRA0_KEYCTRL_FRGB 5 +#define MCDE_CRA0_KEYCTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRA0, KEYCTRL, MCDE_CRA0_KEYCTRL_##__x) +#define MCDE_CRA0_KEYCTRL(__x) \ + MCDE_VAL2REG(MCDE_CRA0, KEYCTRL, __x) +#define MCDE_CRA0_BLENDCTRL_SHIFT 10 +#define MCDE_CRA0_BLENDCTRL_MASK 0x00000400 +#define MCDE_CRA0_BLENDCTRL_SOURCE 0 +#define MCDE_CRA0_BLENDCTRL_CONSTANT 1 +#define MCDE_CRA0_BLENDCTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRA0, BLENDCTRL, MCDE_CRA0_BLENDCTRL_##__x) +#define MCDE_CRA0_BLENDCTRL(__x) \ + MCDE_VAL2REG(MCDE_CRA0, BLENDCTRL, __x) +#define MCDE_CRA0_FLICKMODE_SHIFT 11 +#define MCDE_CRA0_FLICKMODE_MASK 0x00001800 +#define MCDE_CRA0_FLICKMODE_FORCE_FILTER_0 0 +#define MCDE_CRA0_FLICKMODE_ADAPTIVE 1 +#define MCDE_CRA0_FLICKMODE_TEST_MODE 2 +#define MCDE_CRA0_FLICKMODE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRA0, FLICKMODE, MCDE_CRA0_FLICKMODE_##__x) +#define MCDE_CRA0_FLICKMODE(__x) \ + MCDE_VAL2REG(MCDE_CRA0, FLICKMODE, __x) +#define MCDE_CRA0_FLOCKFORMAT_SHIFT 13 +#define MCDE_CRA0_FLOCKFORMAT_MASK 0x00002000 +#define MCDE_CRA0_FLOCKFORMAT_YCBCR 0 +#define MCDE_CRA0_FLOCKFORMAT_RGB 1 +#define MCDE_CRA0_FLOCKFORMAT_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRA0, FLOCKFORMAT, MCDE_CRA0_FLOCKFORMAT_##__x) +#define MCDE_CRA0_FLOCKFORMAT(__x) \ + MCDE_VAL2REG(MCDE_CRA0, FLOCKFORMAT, __x) +#define MCDE_CRA0_PALMODE_SHIFT 14 +#define MCDE_CRA0_PALMODE_MASK 0x00004000 +#define MCDE_CRA0_PALMODE_PALETTE 0 +#define MCDE_CRA0_PALMODE_GAMMA 1 +#define MCDE_CRA0_PALMODE(__x) \ + MCDE_VAL2REG(MCDE_CRA0, PALMODE, __x) +#define MCDE_CRA0_OLEDEN_SHIFT 15 +#define MCDE_CRA0_OLEDEN_MASK 0x00008000 +#define MCDE_CRA0_OLEDEN(__x) \ + MCDE_VAL2REG(MCDE_CRA0, OLEDEN, __x) +#define MCDE_CRA0_ALPHABLEND_SHIFT 16 +#define MCDE_CRA0_ALPHABLEND_MASK 0x00FF0000 +#define MCDE_CRA0_ALPHABLEND(__x) \ + MCDE_VAL2REG(MCDE_CRA0, ALPHABLEND, __x) +#define MCDE_CRA0_ROTEN_SHIFT 24 +#define MCDE_CRA0_ROTEN_MASK 0x01000000 +#define MCDE_CRA0_ROTEN(__x) \ + MCDE_VAL2REG(MCDE_CRA0, ROTEN, __x) +#define MCDE_CRB0 0x00000A00 +#define MCDE_CRB0_FLOEN_SHIFT 0 +#define MCDE_CRB0_FLOEN_MASK 0x00000001 +#define MCDE_CRB0_FLOEN(__x) \ + MCDE_VAL2REG(MCDE_CRB0, FLOEN, __x) +#define MCDE_CRB0_BLENDEN_SHIFT 2 +#define MCDE_CRB0_BLENDEN_MASK 0x00000004 +#define MCDE_CRB0_BLENDEN(__x) \ + MCDE_VAL2REG(MCDE_CRB0, BLENDEN, __x) +#define MCDE_CRB0_AFLICKEN_SHIFT 3 +#define MCDE_CRB0_AFLICKEN_MASK 0x00000008 +#define MCDE_CRB0_AFLICKEN(__x) \ + MCDE_VAL2REG(MCDE_CRB0, AFLICKEN, __x) +#define MCDE_CRB0_PALEN_SHIFT 4 +#define MCDE_CRB0_PALEN_MASK 0x00000010 +#define MCDE_CRB0_PALEN(__x) \ + MCDE_VAL2REG(MCDE_CRB0, PALEN, __x) +#define MCDE_CRB0_DITHEN_SHIFT 5 +#define MCDE_CRB0_DITHEN_MASK 0x00000020 +#define MCDE_CRB0_DITHEN(__x) \ + MCDE_VAL2REG(MCDE_CRB0, DITHEN, __x) +#define MCDE_CRB0_GAMEN_SHIFT 6 +#define MCDE_CRB0_GAMEN_MASK 0x00000040 +#define MCDE_CRB0_GAMEN(__x) \ + MCDE_VAL2REG(MCDE_CRB0, GAMEN, __x) +#define MCDE_CRB0_KEYCTRL_SHIFT 7 +#define MCDE_CRB0_KEYCTRL_MASK 0x00000380 +#define MCDE_CRB0_KEYCTRL_OFF 0 +#define MCDE_CRB0_KEYCTRL_ALPHA_RGB 1 +#define MCDE_CRB0_KEYCTRL_RGB 2 +#define MCDE_CRB0_KEYCTRL_FALPHA_FRGB 4 +#define MCDE_CRB0_KEYCTRL_FRGB 5 +#define MCDE_CRB0_KEYCTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRB0, KEYCTRL, MCDE_CRB0_KEYCTRL_##__x) +#define MCDE_CRB0_KEYCTRL(__x) \ + MCDE_VAL2REG(MCDE_CRB0, KEYCTRL, __x) +#define MCDE_CRB0_BLENDCTRL_SHIFT 10 +#define MCDE_CRB0_BLENDCTRL_MASK 0x00000400 +#define MCDE_CRB0_BLENDCTRL_SOURCE 0 +#define MCDE_CRB0_BLENDCTRL_CONSTANT 1 +#define MCDE_CRB0_BLENDCTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRB0, BLENDCTRL, MCDE_CRB0_BLENDCTRL_##__x) +#define MCDE_CRB0_BLENDCTRL(__x) \ + MCDE_VAL2REG(MCDE_CRB0, BLENDCTRL, __x) +#define MCDE_CRB0_FLICKMODE_SHIFT 11 +#define MCDE_CRB0_FLICKMODE_MASK 0x00001800 +#define MCDE_CRB0_FLICKMODE_FORCE_FILTER_0 0 +#define MCDE_CRB0_FLICKMODE_ADAPTIVE 1 +#define MCDE_CRB0_FLICKMODE_TEST_MODE 2 +#define MCDE_CRB0_FLICKMODE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRB0, FLICKMODE, MCDE_CRB0_FLICKMODE_##__x) +#define MCDE_CRB0_FLICKMODE(__x) \ + MCDE_VAL2REG(MCDE_CRB0, FLICKMODE, __x) +#define MCDE_CRB0_FLOCKFORMAT_SHIFT 13 +#define MCDE_CRB0_FLOCKFORMAT_MASK 0x00002000 +#define MCDE_CRB0_FLOCKFORMAT_YCBCR 0 +#define MCDE_CRB0_FLOCKFORMAT_RGB 1 +#define MCDE_CRB0_FLOCKFORMAT_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRB0, FLOCKFORMAT, MCDE_CRB0_FLOCKFORMAT_##__x) +#define MCDE_CRB0_FLOCKFORMAT(__x) \ + MCDE_VAL2REG(MCDE_CRB0, FLOCKFORMAT, __x) +#define MCDE_CRB0_PALMODE_SHIFT 14 +#define MCDE_CRB0_PALMODE_MASK 0x00004000 +#define MCDE_CRB0_PALMODE_PALETTE 0 +#define MCDE_CRB0_PALMODE_GAMMA 1 +#define MCDE_CRB0_PALMODE(__x) \ + MCDE_VAL2REG(MCDE_CRB0, PALMODE, __x) +#define MCDE_CRB0_OLEDEN_SHIFT 15 +#define MCDE_CRB0_OLEDEN_MASK 0x00008000 +#define MCDE_CRB0_OLEDEN(__x) \ + MCDE_VAL2REG(MCDE_CRB0, OLEDEN, __x) +#define MCDE_CRB0_ALPHABLEND_SHIFT 16 +#define MCDE_CRB0_ALPHABLEND_MASK 0x00FF0000 +#define MCDE_CRB0_ALPHABLEND(__x) \ + MCDE_VAL2REG(MCDE_CRB0, ALPHABLEND, __x) +#define MCDE_CRB0_ROTEN_SHIFT 24 +#define MCDE_CRB0_ROTEN_MASK 0x01000000 +#define MCDE_CRB0_ROTEN(__x) \ + MCDE_VAL2REG(MCDE_CRB0, ROTEN, __x) +#define MCDE_CRA1 0x00000804 +#define MCDE_CRA1_GROUPOFFSET 0x200 +#define MCDE_CRA1_PCD_SHIFT 0 +#define MCDE_CRA1_PCD_MASK 0x000003FF +#define MCDE_CRA1_PCD(__x) \ + MCDE_VAL2REG(MCDE_CRA1, PCD, __x) +#define MCDE_CRA1_CLKSEL_SHIFT 10 +#define MCDE_CRA1_CLKSEL_MASK 0x00001C00 +#define MCDE_CRA1_CLKSEL_CLKPLL72 0 +#define MCDE_CRA1_CLKSEL_CLKPLL27 2 +#define MCDE_CRA1_CLKSEL_TV1CLK 3 +#define MCDE_CRA1_CLKSEL_TV2CLK 4 +#define MCDE_CRA1_CLKSEL_MCDECLK 5 +#define MCDE_CRA1_CLKSEL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRA1, CLKSEL, MCDE_CRA1_CLKSEL_##__x) +#define MCDE_CRA1_CLKSEL(__x) \ + MCDE_VAL2REG(MCDE_CRA1, CLKSEL, __x) +#define MCDE_CRA1_CDWIN_SHIFT 13 +#define MCDE_CRA1_CDWIN_MASK 0x0001E000 +#define MCDE_CRA1_CDWIN_8BPP_C1 0 +#define MCDE_CRA1_CDWIN_12BPP_C1 1 +#define MCDE_CRA1_CDWIN_12BPP_C2 2 +#define MCDE_CRA1_CDWIN_16BPP_C1 3 +#define MCDE_CRA1_CDWIN_16BPP_C2 4 +#define MCDE_CRA1_CDWIN_16BPP_C3 5 +#define MCDE_CRA1_CDWIN_18BPP_C1 6 +#define MCDE_CRA1_CDWIN_18BPP_C2 7 +#define MCDE_CRA1_CDWIN_24BPP 8 +#define MCDE_CRA1_CDWIN_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRA1, CDWIN, MCDE_CRA1_CDWIN_##__x) +#define MCDE_CRA1_CDWIN(__x) \ + MCDE_VAL2REG(MCDE_CRA1, CDWIN, __x) +#define MCDE_CRA1_OUTBPP_SHIFT 25 +#define MCDE_CRA1_OUTBPP_MASK 0x1E000000 +#define MCDE_CRA1_OUTBPP_MONO1 0 +#define MCDE_CRA1_OUTBPP_MONO2 1 +#define MCDE_CRA1_OUTBPP_MONO4 2 +#define MCDE_CRA1_OUTBPP_MONO8 3 +#define MCDE_CRA1_OUTBPP_8BPP 4 +#define MCDE_CRA1_OUTBPP_12BPP 5 +#define MCDE_CRA1_OUTBPP_15BPP 6 +#define MCDE_CRA1_OUTBPP_16BPP 7 +#define MCDE_CRA1_OUTBPP_18BPP 8 +#define MCDE_CRA1_OUTBPP_24BPP 9 +#define MCDE_CRA1_OUTBPP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRA1, OUTBPP, MCDE_CRA1_OUTBPP_##__x) +#define MCDE_CRA1_OUTBPP(__x) \ + MCDE_VAL2REG(MCDE_CRA1, OUTBPP, __x) +#define MCDE_CRA1_BCD_SHIFT 29 +#define MCDE_CRA1_BCD_MASK 0x20000000 +#define MCDE_CRA1_BCD(__x) \ + MCDE_VAL2REG(MCDE_CRA1, BCD, __x) +#define MCDE_CRA1_CLKTYPE_SHIFT 30 +#define MCDE_CRA1_CLKTYPE_MASK 0x40000000 +#define MCDE_CRA1_CLKTYPE_TVXCLKSEL0 0 +#define MCDE_CRA1_CLKTYPE_TVXCLKSEL1 1 +#define MCDE_CRA1_CLKTYPE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRA1, CLKTYPE, MCDE_CRA1_CLKTYPE_##__x) +#define MCDE_CRA1_CLKTYPE(__x) \ + MCDE_VAL2REG(MCDE_CRA1, CLKTYPE, __x) +#define MCDE_CRB1 0x00000A04 +#define MCDE_CRB1_PCD_SHIFT 0 +#define MCDE_CRB1_PCD_MASK 0x000003FF +#define MCDE_CRB1_PCD(__x) \ + MCDE_VAL2REG(MCDE_CRB1, PCD, __x) +#define MCDE_CRB1_CLKSEL_SHIFT 10 +#define MCDE_CRB1_CLKSEL_MASK 0x00001C00 +#define MCDE_CRB1_CLKSEL_CLKPLL72 0 +#define MCDE_CRB1_CLKSEL_CLKPLL27 2 +#define MCDE_CRB1_CLKSEL_TV1CLK 3 +#define MCDE_CRB1_CLKSEL_TV2CLK 4 +#define MCDE_CRB1_CLKSEL_MCDECLK 5 +#define MCDE_CRB1_CLKSEL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRB1, CLKSEL, MCDE_CRB1_CLKSEL_##__x) +#define MCDE_CRB1_CLKSEL(__x) \ + MCDE_VAL2REG(MCDE_CRB1, CLKSEL, __x) +#define MCDE_CRB1_CDWIN_SHIFT 13 +#define MCDE_CRB1_CDWIN_MASK 0x0001E000 +#define MCDE_CRB1_CDWIN_8BPP_C1 0 +#define MCDE_CRB1_CDWIN_12BPP_C1 1 +#define MCDE_CRB1_CDWIN_12BPP_C2 2 +#define MCDE_CRB1_CDWIN_16BPP_C1 3 +#define MCDE_CRB1_CDWIN_16BPP_C2 4 +#define MCDE_CRB1_CDWIN_16BPP_C3 5 +#define MCDE_CRB1_CDWIN_18BPP_C1 6 +#define MCDE_CRB1_CDWIN_18BPP_C2 7 +#define MCDE_CRB1_CDWIN_24BPP 8 +#define MCDE_CRB1_CDWIN_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRB1, CDWIN, MCDE_CRB1_CDWIN_##__x) +#define MCDE_CRB1_CDWIN(__x) \ + MCDE_VAL2REG(MCDE_CRB1, CDWIN, __x) +#define MCDE_CRB1_OUTBPP_SHIFT 25 +#define MCDE_CRB1_OUTBPP_MASK 0x1E000000 +#define MCDE_CRB1_OUTBPP_MONO1 0 +#define MCDE_CRB1_OUTBPP_MONO2 1 +#define MCDE_CRB1_OUTBPP_MONO4 2 +#define MCDE_CRB1_OUTBPP_MONO8 3 +#define MCDE_CRB1_OUTBPP_8BPP 4 +#define MCDE_CRB1_OUTBPP_12BPP 5 +#define MCDE_CRB1_OUTBPP_15BPP 6 +#define MCDE_CRB1_OUTBPP_16BPP 7 +#define MCDE_CRB1_OUTBPP_18BPP 8 +#define MCDE_CRB1_OUTBPP_24BPP 9 +#define MCDE_CRB1_OUTBPP_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRB1, OUTBPP, MCDE_CRB1_OUTBPP_##__x) +#define MCDE_CRB1_OUTBPP(__x) \ + MCDE_VAL2REG(MCDE_CRB1, OUTBPP, __x) +#define MCDE_CRB1_BCD_SHIFT 29 +#define MCDE_CRB1_BCD_MASK 0x20000000 +#define MCDE_CRB1_BCD(__x) \ + MCDE_VAL2REG(MCDE_CRB1, BCD, __x) +#define MCDE_CRB1_CLKTYPE_SHIFT 30 +#define MCDE_CRB1_CLKTYPE_MASK 0x40000000 +#define MCDE_CRB1_CLKTYPE_TVXCLKSEL0 0 +#define MCDE_CRB1_CLKTYPE_TVXCLKSEL1 1 +#define MCDE_CRB1_CLKTYPE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRB1, CLKTYPE, MCDE_CRB1_CLKTYPE_##__x) +#define MCDE_CRB1_CLKTYPE(__x) \ + MCDE_VAL2REG(MCDE_CRB1, CLKTYPE, __x) +#define MCDE_COLKEYA 0x00000808 +#define MCDE_COLKEYA_GROUPOFFSET 0x200 +#define MCDE_COLKEYA_KEYB_SHIFT 0 +#define MCDE_COLKEYA_KEYB_MASK 0x000000FF +#define MCDE_COLKEYA_KEYB(__x) \ + MCDE_VAL2REG(MCDE_COLKEYA, KEYB, __x) +#define MCDE_COLKEYA_KEYG_SHIFT 8 +#define MCDE_COLKEYA_KEYG_MASK 0x0000FF00 +#define MCDE_COLKEYA_KEYG(__x) \ + MCDE_VAL2REG(MCDE_COLKEYA, KEYG, __x) +#define MCDE_COLKEYA_KEYR_SHIFT 16 +#define MCDE_COLKEYA_KEYR_MASK 0x00FF0000 +#define MCDE_COLKEYA_KEYR(__x) \ + MCDE_VAL2REG(MCDE_COLKEYA, KEYR, __x) +#define MCDE_COLKEYA_KEYA_SHIFT 24 +#define MCDE_COLKEYA_KEYA_MASK 0xFF000000 +#define MCDE_COLKEYA_KEYA(__x) \ + MCDE_VAL2REG(MCDE_COLKEYA, KEYA, __x) +#define MCDE_COLKEYB 0x00000A08 +#define MCDE_COLKEYB_KEYB_SHIFT 0 +#define MCDE_COLKEYB_KEYB_MASK 0x000000FF +#define MCDE_COLKEYB_KEYB(__x) \ + MCDE_VAL2REG(MCDE_COLKEYB, KEYB, __x) +#define MCDE_COLKEYB_KEYG_SHIFT 8 +#define MCDE_COLKEYB_KEYG_MASK 0x0000FF00 +#define MCDE_COLKEYB_KEYG(__x) \ + MCDE_VAL2REG(MCDE_COLKEYB, KEYG, __x) +#define MCDE_COLKEYB_KEYR_SHIFT 16 +#define MCDE_COLKEYB_KEYR_MASK 0x00FF0000 +#define MCDE_COLKEYB_KEYR(__x) \ + MCDE_VAL2REG(MCDE_COLKEYB, KEYR, __x) +#define MCDE_COLKEYB_KEYA_SHIFT 24 +#define MCDE_COLKEYB_KEYA_MASK 0xFF000000 +#define MCDE_COLKEYB_KEYA(__x) \ + MCDE_VAL2REG(MCDE_COLKEYB, KEYA, __x) +#define MCDE_FCOLKEYA 0x0000080C +#define MCDE_FCOLKEYA_GROUPOFFSET 0x200 +#define MCDE_FCOLKEYA_FKEYB_SHIFT 0 +#define MCDE_FCOLKEYA_FKEYB_MASK 0x000000FF +#define MCDE_FCOLKEYA_FKEYB(__x) \ + MCDE_VAL2REG(MCDE_FCOLKEYA, FKEYB, __x) +#define MCDE_FCOLKEYA_FKEYG_SHIFT 8 +#define MCDE_FCOLKEYA_FKEYG_MASK 0x0000FF00 +#define MCDE_FCOLKEYA_FKEYG(__x) \ + MCDE_VAL2REG(MCDE_FCOLKEYA, FKEYG, __x) +#define MCDE_FCOLKEYA_FKEYR_SHIFT 16 +#define MCDE_FCOLKEYA_FKEYR_MASK 0x00FF0000 +#define MCDE_FCOLKEYA_FKEYR(__x) \ + MCDE_VAL2REG(MCDE_FCOLKEYA, FKEYR, __x) +#define MCDE_FCOLKEYA_FKEYA_SHIFT 24 +#define MCDE_FCOLKEYA_FKEYA_MASK 0xFF000000 +#define MCDE_FCOLKEYA_FKEYA(__x) \ + MCDE_VAL2REG(MCDE_FCOLKEYA, FKEYA, __x) +#define MCDE_FCOLKEYB 0x00000A0C +#define MCDE_FCOLKEYB_FKEYB_SHIFT 0 +#define MCDE_FCOLKEYB_FKEYB_MASK 0x000000FF +#define MCDE_FCOLKEYB_FKEYB(__x) \ + MCDE_VAL2REG(MCDE_FCOLKEYB, FKEYB, __x) +#define MCDE_FCOLKEYB_FKEYG_SHIFT 8 +#define MCDE_FCOLKEYB_FKEYG_MASK 0x0000FF00 +#define MCDE_FCOLKEYB_FKEYG(__x) \ + MCDE_VAL2REG(MCDE_FCOLKEYB, FKEYG, __x) +#define MCDE_FCOLKEYB_FKEYR_SHIFT 16 +#define MCDE_FCOLKEYB_FKEYR_MASK 0x00FF0000 +#define MCDE_FCOLKEYB_FKEYR(__x) \ + MCDE_VAL2REG(MCDE_FCOLKEYB, FKEYR, __x) +#define MCDE_FCOLKEYB_FKEYA_SHIFT 24 +#define MCDE_FCOLKEYB_FKEYA_MASK 0xFF000000 +#define MCDE_FCOLKEYB_FKEYA(__x) \ + MCDE_VAL2REG(MCDE_FCOLKEYB, FKEYA, __x) +#define MCDE_RGBCONV1A 0x00000810 +#define MCDE_RGBCONV1A_GROUPOFFSET 0x200 +#define MCDE_RGBCONV1A_YR_GREEN_SHIFT 0 +#define MCDE_RGBCONV1A_YR_GREEN_MASK 0x000007FF +#define MCDE_RGBCONV1A_YR_GREEN(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV1A, YR_GREEN, __x) +#define MCDE_RGBCONV1A_YR_RED_SHIFT 16 +#define MCDE_RGBCONV1A_YR_RED_MASK 0x07FF0000 +#define MCDE_RGBCONV1A_YR_RED(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV1A, YR_RED, __x) +#define MCDE_RGBCONV1B 0x00000A10 +#define MCDE_RGBCONV1B_YR_GREEN_SHIFT 0 +#define MCDE_RGBCONV1B_YR_GREEN_MASK 0x000007FF +#define MCDE_RGBCONV1B_YR_GREEN(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV1B, YR_GREEN, __x) +#define MCDE_RGBCONV1B_YR_RED_SHIFT 16 +#define MCDE_RGBCONV1B_YR_RED_MASK 0x07FF0000 +#define MCDE_RGBCONV1B_YR_RED(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV1B, YR_RED, __x) +#define MCDE_RGBCONV2A 0x00000814 +#define MCDE_RGBCONV2A_GROUPOFFSET 0x200 +#define MCDE_RGBCONV2A_CR_RED_SHIFT 0 +#define MCDE_RGBCONV2A_CR_RED_MASK 0x000007FF +#define MCDE_RGBCONV2A_CR_RED(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV2A, CR_RED, __x) +#define MCDE_RGBCONV2A_YR_BLUE_SHIFT 16 +#define MCDE_RGBCONV2A_YR_BLUE_MASK 0x07FF0000 +#define MCDE_RGBCONV2A_YR_BLUE(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV2A, YR_BLUE, __x) +#define MCDE_RGBCONV2B 0x00000A14 +#define MCDE_RGBCONV2B_CR_RED_SHIFT 0 +#define MCDE_RGBCONV2B_CR_RED_MASK 0x000007FF +#define MCDE_RGBCONV2B_CR_RED(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV2B, CR_RED, __x) +#define MCDE_RGBCONV2B_YR_BLUE_SHIFT 16 +#define MCDE_RGBCONV2B_YR_BLUE_MASK 0x07FF0000 +#define MCDE_RGBCONV2B_YR_BLUE(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV2B, YR_BLUE, __x) +#define MCDE_RGBCONV3A 0x00000818 +#define MCDE_RGBCONV3A_GROUPOFFSET 0x200 +#define MCDE_RGBCONV3A_CR_BLUE_SHIFT 0 +#define MCDE_RGBCONV3A_CR_BLUE_MASK 0x000007FF +#define MCDE_RGBCONV3A_CR_BLUE(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV3A, CR_BLUE, __x) +#define MCDE_RGBCONV3A_CR_GREEN_SHIFT 16 +#define MCDE_RGBCONV3A_CR_GREEN_MASK 0x07FF0000 +#define MCDE_RGBCONV3A_CR_GREEN(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV3A, CR_GREEN, __x) +#define MCDE_RGBCONV3B 0x00000A18 +#define MCDE_RGBCONV3B_CR_BLUE_SHIFT 0 +#define MCDE_RGBCONV3B_CR_BLUE_MASK 0x000007FF +#define MCDE_RGBCONV3B_CR_BLUE(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV3B, CR_BLUE, __x) +#define MCDE_RGBCONV3B_CR_GREEN_SHIFT 16 +#define MCDE_RGBCONV3B_CR_GREEN_MASK 0x07FF0000 +#define MCDE_RGBCONV3B_CR_GREEN(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV3B, CR_GREEN, __x) +#define MCDE_RGBCONV4A 0x0000081C +#define MCDE_RGBCONV4A_GROUPOFFSET 0x200 +#define MCDE_RGBCONV4A_CB_GREEN_SHIFT 0 +#define MCDE_RGBCONV4A_CB_GREEN_MASK 0x000007FF +#define MCDE_RGBCONV4A_CB_GREEN(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV4A, CB_GREEN, __x) +#define MCDE_RGBCONV4A_CB_RED_SHIFT 16 +#define MCDE_RGBCONV4A_CB_RED_MASK 0x07FF0000 +#define MCDE_RGBCONV4A_CB_RED(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV4A, CB_RED, __x) +#define MCDE_RGBCONV4B 0x00000A1C +#define MCDE_RGBCONV4B_CB_GREEN_SHIFT 0 +#define MCDE_RGBCONV4B_CB_GREEN_MASK 0x000007FF +#define MCDE_RGBCONV4B_CB_GREEN(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV4B, CB_GREEN, __x) +#define MCDE_RGBCONV4B_CB_RED_SHIFT 16 +#define MCDE_RGBCONV4B_CB_RED_MASK 0x07FF0000 +#define MCDE_RGBCONV4B_CB_RED(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV4B, CB_RED, __x) +#define MCDE_RGBCONV5A 0x00000820 +#define MCDE_RGBCONV5A_GROUPOFFSET 0x200 +#define MCDE_RGBCONV5A_OFF_RED_SHIFT 0 +#define MCDE_RGBCONV5A_OFF_RED_MASK 0x000007FF +#define MCDE_RGBCONV5A_OFF_RED(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV5A, OFF_RED, __x) +#define MCDE_RGBCONV5A_CB_BLUE_SHIFT 16 +#define MCDE_RGBCONV5A_CB_BLUE_MASK 0x07FF0000 +#define MCDE_RGBCONV5A_CB_BLUE(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV5A, CB_BLUE, __x) +#define MCDE_RGBCONV5B 0x00000A20 +#define MCDE_RGBCONV5B_OFF_RED_SHIFT 0 +#define MCDE_RGBCONV5B_OFF_RED_MASK 0x000007FF +#define MCDE_RGBCONV5B_OFF_RED(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV5B, OFF_RED, __x) +#define MCDE_RGBCONV5B_CB_BLUE_SHIFT 16 +#define MCDE_RGBCONV5B_CB_BLUE_MASK 0x07FF0000 +#define MCDE_RGBCONV5B_CB_BLUE(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV5B, CB_BLUE, __x) +#define MCDE_RGBCONV6A 0x00000824 +#define MCDE_RGBCONV6A_GROUPOFFSET 0x200 +#define MCDE_RGBCONV6A_OFF_BLUE_SHIFT 0 +#define MCDE_RGBCONV6A_OFF_BLUE_MASK 0x000007FF +#define MCDE_RGBCONV6A_OFF_BLUE(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV6A, OFF_BLUE, __x) +#define MCDE_RGBCONV6A_OFF_GREEN_SHIFT 16 +#define MCDE_RGBCONV6A_OFF_GREEN_MASK 0x07FF0000 +#define MCDE_RGBCONV6A_OFF_GREEN(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV6A, OFF_GREEN, __x) +#define MCDE_RGBCONV6B 0x00000A24 +#define MCDE_RGBCONV6B_OFF_BLUE_SHIFT 0 +#define MCDE_RGBCONV6B_OFF_BLUE_MASK 0x000007FF +#define MCDE_RGBCONV6B_OFF_BLUE(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV6B, OFF_BLUE, __x) +#define MCDE_RGBCONV6B_OFF_GREEN_SHIFT 16 +#define MCDE_RGBCONV6B_OFF_GREEN_MASK 0x07FF0000 +#define MCDE_RGBCONV6B_OFF_GREEN(__x) \ + MCDE_VAL2REG(MCDE_RGBCONV6B, OFF_GREEN, __x) +#define MCDE_FFCOEF0 0x00000828 +#define MCDE_FFCOEF0_COEFF0_N1_SHIFT 0 +#define MCDE_FFCOEF0_COEFF0_N1_MASK 0x000000FF +#define MCDE_FFCOEF0_COEFF0_N1(__x) \ + MCDE_VAL2REG(MCDE_FFCOEF0, COEFF0_N1, __x) +#define MCDE_FFCOEF0_COEFF0_N2_SHIFT 8 +#define MCDE_FFCOEF0_COEFF0_N2_MASK 0x0000FF00 +#define MCDE_FFCOEF0_COEFF0_N2(__x) \ + MCDE_VAL2REG(MCDE_FFCOEF0, COEFF0_N2, __x) +#define MCDE_FFCOEF0_COEFF0_N3_SHIFT 16 +#define MCDE_FFCOEF0_COEFF0_N3_MASK 0x00FF0000 +#define MCDE_FFCOEF0_COEFF0_N3(__x) \ + MCDE_VAL2REG(MCDE_FFCOEF0, COEFF0_N3, __x) +#define MCDE_FFCOEF0_T0_SHIFT 24 +#define MCDE_FFCOEF0_T0_MASK 0x0F000000 +#define MCDE_FFCOEF0_T0(__x) \ + MCDE_VAL2REG(MCDE_FFCOEF0, T0, __x) +#define MCDE_FFCOEF1 0x0000082C +#define MCDE_FFCOEF1_COEFF1_N1_SHIFT 0 +#define MCDE_FFCOEF1_COEFF1_N1_MASK 0x000000FF +#define MCDE_FFCOEF1_COEFF1_N1(__x) \ + MCDE_VAL2REG(MCDE_FFCOEF1, COEFF1_N1, __x) +#define MCDE_FFCOEF1_COEFF1_N2_SHIFT 8 +#define MCDE_FFCOEF1_COEFF1_N2_MASK 0x0000FF00 +#define MCDE_FFCOEF1_COEFF1_N2(__x) \ + MCDE_VAL2REG(MCDE_FFCOEF1, COEFF1_N2, __x) +#define MCDE_FFCOEF1_COEFF1_N3_SHIFT 16 +#define MCDE_FFCOEF1_COEFF1_N3_MASK 0x00FF0000 +#define MCDE_FFCOEF1_COEFF1_N3(__x) \ + MCDE_VAL2REG(MCDE_FFCOEF1, COEFF1_N3, __x) +#define MCDE_FFCOEF1_T1_SHIFT 24 +#define MCDE_FFCOEF1_T1_MASK 0x0F000000 +#define MCDE_FFCOEF1_T1(__x) \ + MCDE_VAL2REG(MCDE_FFCOEF1, T1, __x) +#define MCDE_FFCOEF2 0x00000830 +#define MCDE_FFCOEF2_COEFF2_N1_SHIFT 0 +#define MCDE_FFCOEF2_COEFF2_N1_MASK 0x000000FF +#define MCDE_FFCOEF2_COEFF2_N1(__x) \ + MCDE_VAL2REG(MCDE_FFCOEF2, COEFF2_N1, __x) +#define MCDE_FFCOEF2_COEFF2_N2_SHIFT 8 +#define MCDE_FFCOEF2_COEFF2_N2_MASK 0x0000FF00 +#define MCDE_FFCOEF2_COEFF2_N2(__x) \ + MCDE_VAL2REG(MCDE_FFCOEF2, COEFF2_N2, __x) +#define MCDE_FFCOEF2_COEFF2_N3_SHIFT 16 +#define MCDE_FFCOEF2_COEFF2_N3_MASK 0x00FF0000 +#define MCDE_FFCOEF2_COEFF2_N3(__x) \ + MCDE_VAL2REG(MCDE_FFCOEF2, COEFF2_N3, __x) +#define MCDE_FFCOEF2_T2_SHIFT 24 +#define MCDE_FFCOEF2_T2_MASK 0x0F000000 +#define MCDE_FFCOEF2_T2(__x) \ + MCDE_VAL2REG(MCDE_FFCOEF2, T2, __x) +#define MCDE_MCDE_WDATAA 0x00000834 +#define MCDE_MCDE_WDATAA_GROUPOFFSET 0x200 +#define MCDE_MCDE_WDATAA_DC_SHIFT 24 +#define MCDE_MCDE_WDATAA_DC_MASK 0x01000000 +#define MCDE_MCDE_WDATAA_DC(__x) \ + MCDE_VAL2REG(MCDE_MCDE_WDATAA, DC, __x) +#define MCDE_MCDE_WDATAA_DATAVALUE_SHIFT 0 +#define MCDE_MCDE_WDATAA_DATAVALUE_MASK 0x00FFFFFF +#define MCDE_MCDE_WDATAA_DATAVALUE(__x) \ + MCDE_VAL2REG(MCDE_MCDE_WDATAA, DATAVALUE, __x) +#define MCDE_MCDE_WDATAB 0x00000A34 +#define MCDE_MCDE_WDATAB_DC_SHIFT 24 +#define MCDE_MCDE_WDATAB_DC_MASK 0x01000000 +#define MCDE_MCDE_WDATAB_DC(__x) \ + MCDE_VAL2REG(MCDE_MCDE_WDATAB, DC, __x) +#define MCDE_MCDE_WDATAB_DATAVALUE_SHIFT 0 +#define MCDE_MCDE_WDATAB_DATAVALUE_MASK 0x00FFFFFF +#define MCDE_MCDE_WDATAB_DATAVALUE(__x) \ + MCDE_VAL2REG(MCDE_MCDE_WDATAB, DATAVALUE, __x) +#define MCDE_TVCRA 0x00000838 +#define MCDE_TVCRA_GROUPOFFSET 0x200 +#define MCDE_TVCRA_SEL_MOD_SHIFT 0 +#define MCDE_TVCRA_SEL_MOD_MASK 0x00000001 +#define MCDE_TVCRA_SEL_MOD_LCD 0 +#define MCDE_TVCRA_SEL_MOD_TV 1 +#define MCDE_TVCRA_SEL_MOD_ENUM(__x) \ + MCDE_VAL2REG(MCDE_TVCRA, SEL_MOD, MCDE_TVCRA_SEL_MOD_##__x) +#define MCDE_TVCRA_SEL_MOD(__x) \ + MCDE_VAL2REG(MCDE_TVCRA, SEL_MOD, __x) +#define MCDE_TVCRA_INTEREN_SHIFT 1 +#define MCDE_TVCRA_INTEREN_MASK 0x00000002 +#define MCDE_TVCRA_INTEREN(__x) \ + MCDE_VAL2REG(MCDE_TVCRA, INTEREN, __x) +#define MCDE_TVCRA_IFIELD_SHIFT 2 +#define MCDE_TVCRA_IFIELD_MASK 0x00000004 +#define MCDE_TVCRA_IFIELD(__x) \ + MCDE_VAL2REG(MCDE_TVCRA, IFIELD, __x) +#define MCDE_TVCRA_TVMODE_SHIFT 3 +#define MCDE_TVCRA_TVMODE_MASK 0x00000038 +#define MCDE_TVCRA_TVMODE_SDTV_656P 0 +#define MCDE_TVCRA_TVMODE_SDTV_656P_LE 3 +#define MCDE_TVCRA_TVMODE_SDTV_656P_BE 4 +#define MCDE_TVCRA_TVMODE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_TVCRA, TVMODE, MCDE_TVCRA_TVMODE_##__x) +#define MCDE_TVCRA_TVMODE(__x) \ + MCDE_VAL2REG(MCDE_TVCRA, TVMODE, __x) +#define MCDE_TVCRA_SDTVMODE_SHIFT 6 +#define MCDE_TVCRA_SDTVMODE_MASK 0x000000C0 +#define MCDE_TVCRA_SDTVMODE_Y0CBY1CR 0 +#define MCDE_TVCRA_SDTVMODE_CBY0CRY1 1 +#define MCDE_TVCRA_SDTVMODE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_TVCRA, SDTVMODE, MCDE_TVCRA_SDTVMODE_##__x) +#define MCDE_TVCRA_SDTVMODE(__x) \ + MCDE_VAL2REG(MCDE_TVCRA, SDTVMODE, __x) +#define MCDE_TVCRA_AVRGEN_SHIFT 8 +#define MCDE_TVCRA_AVRGEN_MASK 0x00000100 +#define MCDE_TVCRA_AVRGEN(__x) \ + MCDE_VAL2REG(MCDE_TVCRA, AVRGEN, __x) +#define MCDE_TVCRA_CKINV_SHIFT 9 +#define MCDE_TVCRA_CKINV_MASK 0x00000200 +#define MCDE_TVCRA_CKINV(__x) \ + MCDE_VAL2REG(MCDE_TVCRA, CKINV, __x) +#define MCDE_TVCRB 0x00000A38 +#define MCDE_TVCRB_SEL_MOD_SHIFT 0 +#define MCDE_TVCRB_SEL_MOD_MASK 0x00000001 +#define MCDE_TVCRB_SEL_MOD_LCD 0 +#define MCDE_TVCRB_SEL_MOD_TV 1 +#define MCDE_TVCRB_SEL_MOD_ENUM(__x) \ + MCDE_VAL2REG(MCDE_TVCRB, SEL_MOD, MCDE_TVCRB_SEL_MOD_##__x) +#define MCDE_TVCRB_SEL_MOD(__x) \ + MCDE_VAL2REG(MCDE_TVCRB, SEL_MOD, __x) +#define MCDE_TVCRB_INTEREN_SHIFT 1 +#define MCDE_TVCRB_INTEREN_MASK 0x00000002 +#define MCDE_TVCRB_INTEREN(__x) \ + MCDE_VAL2REG(MCDE_TVCRB, INTEREN, __x) +#define MCDE_TVCRB_IFIELD_SHIFT 2 +#define MCDE_TVCRB_IFIELD_MASK 0x00000004 +#define MCDE_TVCRB_IFIELD(__x) \ + MCDE_VAL2REG(MCDE_TVCRB, IFIELD, __x) +#define MCDE_TVCRB_TVMODE_SHIFT 3 +#define MCDE_TVCRB_TVMODE_MASK 0x00000038 +#define MCDE_TVCRB_TVMODE_SDTV_656P 0 +#define MCDE_TVCRB_TVMODE_SDTV_656P_LE 3 +#define MCDE_TVCRB_TVMODE_SDTV_656P_BE 4 +#define MCDE_TVCRB_TVMODE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_TVCRB, TVMODE, MCDE_TVCRB_TVMODE_##__x) +#define MCDE_TVCRB_TVMODE(__x) \ + MCDE_VAL2REG(MCDE_TVCRB, TVMODE, __x) +#define MCDE_TVCRB_SDTVMODE_SHIFT 6 +#define MCDE_TVCRB_SDTVMODE_MASK 0x000000C0 +#define MCDE_TVCRB_SDTVMODE_Y0CBY1CR 0 +#define MCDE_TVCRB_SDTVMODE_CBY0CRY1 1 +#define MCDE_TVCRB_SDTVMODE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_TVCRB, SDTVMODE, MCDE_TVCRB_SDTVMODE_##__x) +#define MCDE_TVCRB_SDTVMODE(__x) \ + MCDE_VAL2REG(MCDE_TVCRB, SDTVMODE, __x) +#define MCDE_TVCRB_AVRGEN_SHIFT 8 +#define MCDE_TVCRB_AVRGEN_MASK 0x00000100 +#define MCDE_TVCRB_AVRGEN(__x) \ + MCDE_VAL2REG(MCDE_TVCRB, AVRGEN, __x) +#define MCDE_TVCRB_CKINV_SHIFT 9 +#define MCDE_TVCRB_CKINV_MASK 0x00000200 +#define MCDE_TVCRB_CKINV(__x) \ + MCDE_VAL2REG(MCDE_TVCRB, CKINV, __x) +#define MCDE_TVBL1A 0x0000083C +#define MCDE_TVBL1A_GROUPOFFSET 0x200 +#define MCDE_TVBL1A_BEL1_SHIFT 0 +#define MCDE_TVBL1A_BEL1_MASK 0x000007FF +#define MCDE_TVBL1A_BEL1(__x) \ + MCDE_VAL2REG(MCDE_TVBL1A, BEL1, __x) +#define MCDE_TVBL1A_BSL1_SHIFT 16 +#define MCDE_TVBL1A_BSL1_MASK 0x07FF0000 +#define MCDE_TVBL1A_BSL1(__x) \ + MCDE_VAL2REG(MCDE_TVBL1A, BSL1, __x) +#define MCDE_TVBL1B 0x00000A3C +#define MCDE_TVBL1B_BEL1_SHIFT 0 +#define MCDE_TVBL1B_BEL1_MASK 0x000007FF +#define MCDE_TVBL1B_BEL1(__x) \ + MCDE_VAL2REG(MCDE_TVBL1B, BEL1, __x) +#define MCDE_TVBL1B_BSL1_SHIFT 16 +#define MCDE_TVBL1B_BSL1_MASK 0x07FF0000 +#define MCDE_TVBL1B_BSL1(__x) \ + MCDE_VAL2REG(MCDE_TVBL1B, BSL1, __x) +#define MCDE_TVISLA 0x00000840 +#define MCDE_TVISLA_GROUPOFFSET 0x200 +#define MCDE_TVISLA_FSL1_SHIFT 0 +#define MCDE_TVISLA_FSL1_MASK 0x000007FF +#define MCDE_TVISLA_FSL1(__x) \ + MCDE_VAL2REG(MCDE_TVISLA, FSL1, __x) +#define MCDE_TVISLA_FSL2_SHIFT 16 +#define MCDE_TVISLA_FSL2_MASK 0x07FF0000 +#define MCDE_TVISLA_FSL2(__x) \ + MCDE_VAL2REG(MCDE_TVISLA, FSL2, __x) +#define MCDE_TVISLB 0x00000A40 +#define MCDE_TVISLB_FSL1_SHIFT 0 +#define MCDE_TVISLB_FSL1_MASK 0x000007FF +#define MCDE_TVISLB_FSL1(__x) \ + MCDE_VAL2REG(MCDE_TVISLB, FSL1, __x) +#define MCDE_TVISLB_FSL2_SHIFT 16 +#define MCDE_TVISLB_FSL2_MASK 0x07FF0000 +#define MCDE_TVISLB_FSL2(__x) \ + MCDE_VAL2REG(MCDE_TVISLB, FSL2, __x) +#define MCDE_TVDVOA 0x00000844 +#define MCDE_TVDVOA_GROUPOFFSET 0x200 +#define MCDE_TVDVOA_DVO1_SHIFT 0 +#define MCDE_TVDVOA_DVO1_MASK 0x000007FF +#define MCDE_TVDVOA_DVO1(__x) \ + MCDE_VAL2REG(MCDE_TVDVOA, DVO1, __x) +#define MCDE_TVDVOA_DVO2_SHIFT 16 +#define MCDE_TVDVOA_DVO2_MASK 0x07FF0000 +#define MCDE_TVDVOA_DVO2(__x) \ + MCDE_VAL2REG(MCDE_TVDVOA, DVO2, __x) +#define MCDE_TVDVOB 0x00000A44 +#define MCDE_TVDVOB_DVO1_SHIFT 0 +#define MCDE_TVDVOB_DVO1_MASK 0x000007FF +#define MCDE_TVDVOB_DVO1(__x) \ + MCDE_VAL2REG(MCDE_TVDVOB, DVO1, __x) +#define MCDE_TVDVOB_DVO2_SHIFT 16 +#define MCDE_TVDVOB_DVO2_MASK 0x07FF0000 +#define MCDE_TVDVOB_DVO2(__x) \ + MCDE_VAL2REG(MCDE_TVDVOB, DVO2, __x) +#define MCDE_TVTIM1A 0x0000084C +#define MCDE_TVTIM1A_GROUPOFFSET 0x200 +#define MCDE_TVTIM1A_DHO_SHIFT 0 +#define MCDE_TVTIM1A_DHO_MASK 0x000007FF +#define MCDE_TVTIM1A_DHO(__x) \ + MCDE_VAL2REG(MCDE_TVTIM1A, DHO, __x) +#define MCDE_TVTIM1B 0x00000A4C +#define MCDE_TVTIM1B_DHO_SHIFT 0 +#define MCDE_TVTIM1B_DHO_MASK 0x000007FF +#define MCDE_TVTIM1B_DHO(__x) \ + MCDE_VAL2REG(MCDE_TVTIM1B, DHO, __x) +#define MCDE_TVLBALWA 0x00000850 +#define MCDE_TVLBALWA_GROUPOFFSET 0x200 +#define MCDE_TVLBALWA_LBW_SHIFT 0 +#define MCDE_TVLBALWA_LBW_MASK 0x000007FF +#define MCDE_TVLBALWA_LBW(__x) \ + MCDE_VAL2REG(MCDE_TVLBALWA, LBW, __x) +#define MCDE_TVLBALWA_ALW_SHIFT 16 +#define MCDE_TVLBALWA_ALW_MASK 0x07FF0000 +#define MCDE_TVLBALWA_ALW(__x) \ + MCDE_VAL2REG(MCDE_TVLBALWA, ALW, __x) +#define MCDE_TVLBALWB 0x00000A50 +#define MCDE_TVLBALWB_LBW_SHIFT 0 +#define MCDE_TVLBALWB_LBW_MASK 0x000007FF +#define MCDE_TVLBALWB_LBW(__x) \ + MCDE_VAL2REG(MCDE_TVLBALWB, LBW, __x) +#define MCDE_TVLBALWB_ALW_SHIFT 16 +#define MCDE_TVLBALWB_ALW_MASK 0x07FF0000 +#define MCDE_TVLBALWB_ALW(__x) \ + MCDE_VAL2REG(MCDE_TVLBALWB, ALW, __x) +#define MCDE_TVBL2A 0x00000854 +#define MCDE_TVBL2A_GROUPOFFSET 0x200 +#define MCDE_TVBL2A_BEL2_SHIFT 0 +#define MCDE_TVBL2A_BEL2_MASK 0x000007FF +#define MCDE_TVBL2A_BEL2(__x) \ + MCDE_VAL2REG(MCDE_TVBL2A, BEL2, __x) +#define MCDE_TVBL2A_BSL2_SHIFT 16 +#define MCDE_TVBL2A_BSL2_MASK 0x07FF0000 +#define MCDE_TVBL2A_BSL2(__x) \ + MCDE_VAL2REG(MCDE_TVBL2A, BSL2, __x) +#define MCDE_TVBL2B 0x00000A54 +#define MCDE_TVBL2B_BEL2_SHIFT 0 +#define MCDE_TVBL2B_BEL2_MASK 0x000007FF +#define MCDE_TVBL2B_BEL2(__x) \ + MCDE_VAL2REG(MCDE_TVBL2B, BEL2, __x) +#define MCDE_TVBL2B_BSL2_SHIFT 16 +#define MCDE_TVBL2B_BSL2_MASK 0x07FF0000 +#define MCDE_TVBL2B_BSL2(__x) \ + MCDE_VAL2REG(MCDE_TVBL2B, BSL2, __x) +#define MCDE_TVBLUA 0x00000858 +#define MCDE_TVBLUA_GROUPOFFSET 0x200 +#define MCDE_TVBLUA_TVBLU_SHIFT 0 +#define MCDE_TVBLUA_TVBLU_MASK 0x000000FF +#define MCDE_TVBLUA_TVBLU(__x) \ + MCDE_VAL2REG(MCDE_TVBLUA, TVBLU, __x) +#define MCDE_TVBLUA_TVBCB_SHIFT 8 +#define MCDE_TVBLUA_TVBCB_MASK 0x0000FF00 +#define MCDE_TVBLUA_TVBCB(__x) \ + MCDE_VAL2REG(MCDE_TVBLUA, TVBCB, __x) +#define MCDE_TVBLUA_TVBCR_SHIFT 16 +#define MCDE_TVBLUA_TVBCR_MASK 0x00FF0000 +#define MCDE_TVBLUA_TVBCR(__x) \ + MCDE_VAL2REG(MCDE_TVBLUA, TVBCR, __x) +#define MCDE_TVBLUB 0x00000A58 +#define MCDE_TVBLUB_TVBLU_SHIFT 0 +#define MCDE_TVBLUB_TVBLU_MASK 0x000000FF +#define MCDE_TVBLUB_TVBLU(__x) \ + MCDE_VAL2REG(MCDE_TVBLUB, TVBLU, __x) +#define MCDE_TVBLUB_TVBCB_SHIFT 8 +#define MCDE_TVBLUB_TVBCB_MASK 0x0000FF00 +#define MCDE_TVBLUB_TVBCB(__x) \ + MCDE_VAL2REG(MCDE_TVBLUB, TVBCB, __x) +#define MCDE_TVBLUB_TVBCR_SHIFT 16 +#define MCDE_TVBLUB_TVBCR_MASK 0x00FF0000 +#define MCDE_TVBLUB_TVBCR(__x) \ + MCDE_VAL2REG(MCDE_TVBLUB, TVBCR, __x) +#define MCDE_LCDTIM1A 0x00000860 +#define MCDE_LCDTIM1A_GROUPOFFSET 0x200 +#define MCDE_LCDTIM1A_IVP_SHIFT 19 +#define MCDE_LCDTIM1A_IVP_MASK 0x00080000 +#define MCDE_LCDTIM1A_IVP(__x) \ + MCDE_VAL2REG(MCDE_LCDTIM1A, IVP, __x) +#define MCDE_LCDTIM1A_IVS_SHIFT 20 +#define MCDE_LCDTIM1A_IVS_MASK 0x00100000 +#define MCDE_LCDTIM1A_IVS(__x) \ + MCDE_VAL2REG(MCDE_LCDTIM1A, IVS, __x) +#define MCDE_LCDTIM1A_IHS_SHIFT 21 +#define MCDE_LCDTIM1A_IHS_MASK 0x00200000 +#define MCDE_LCDTIM1A_IHS(__x) \ + MCDE_VAL2REG(MCDE_LCDTIM1A, IHS, __x) +#define MCDE_LCDTIM1A_IPC_SHIFT 22 +#define MCDE_LCDTIM1A_IPC_MASK 0x00400000 +#define MCDE_LCDTIM1A_IPC(__x) \ + MCDE_VAL2REG(MCDE_LCDTIM1A, IPC, __x) +#define MCDE_LCDTIM1A_IOE_SHIFT 23 +#define MCDE_LCDTIM1A_IOE_MASK 0x00800000 +#define MCDE_LCDTIM1A_IOE(__x) \ + MCDE_VAL2REG(MCDE_LCDTIM1A, IOE, __x) +#define MCDE_LCDTIM1B 0x00000A60 +#define MCDE_LCDTIM1B_IVP_SHIFT 19 +#define MCDE_LCDTIM1B_IVP_MASK 0x00080000 +#define MCDE_LCDTIM1B_IVP(__x) \ + MCDE_VAL2REG(MCDE_LCDTIM1B, IVP, __x) +#define MCDE_LCDTIM1B_IVS_SHIFT 20 +#define MCDE_LCDTIM1B_IVS_MASK 0x00100000 +#define MCDE_LCDTIM1B_IVS(__x) \ + MCDE_VAL2REG(MCDE_LCDTIM1B, IVS, __x) +#define MCDE_LCDTIM1B_IHS_SHIFT 21 +#define MCDE_LCDTIM1B_IHS_MASK 0x00200000 +#define MCDE_LCDTIM1B_IHS(__x) \ + MCDE_VAL2REG(MCDE_LCDTIM1B, IHS, __x) +#define MCDE_LCDTIM1B_IPC_SHIFT 22 +#define MCDE_LCDTIM1B_IPC_MASK 0x00400000 +#define MCDE_LCDTIM1B_IPC(__x) \ + MCDE_VAL2REG(MCDE_LCDTIM1B, IPC, __x) +#define MCDE_LCDTIM1B_IOE_SHIFT 23 +#define MCDE_LCDTIM1B_IOE_MASK 0x00800000 +#define MCDE_LCDTIM1B_IOE(__x) \ + MCDE_VAL2REG(MCDE_LCDTIM1B, IOE, __x) +#define MCDE_DITCTRLA 0x00000864 +#define MCDE_DITCTRLA_GROUPOFFSET 0x200 +#define MCDE_DITCTRLA_TEMP_SHIFT 0 +#define MCDE_DITCTRLA_TEMP_MASK 0x00000001 +#define MCDE_DITCTRLA_TEMP(__x) \ + MCDE_VAL2REG(MCDE_DITCTRLA, TEMP, __x) +#define MCDE_DITCTRLA_COMP_SHIFT 1 +#define MCDE_DITCTRLA_COMP_MASK 0x00000002 +#define MCDE_DITCTRLA_COMP(__x) \ + MCDE_VAL2REG(MCDE_DITCTRLA, COMP, __x) +#define MCDE_DITCTRLA_MODE_SHIFT 2 +#define MCDE_DITCTRLA_MODE_MASK 0x0000000C +#define MCDE_DITCTRLA_MODE(__x) \ + MCDE_VAL2REG(MCDE_DITCTRLA, MODE, __x) +#define MCDE_DITCTRLA_MASK_SHIFT 4 +#define MCDE_DITCTRLA_MASK_MASK 0x00000010 +#define MCDE_DITCTRLA_MASK(__x) \ + MCDE_VAL2REG(MCDE_DITCTRLA, MASK, __x) +#define MCDE_DITCTRLA_FOFFX_SHIFT 5 +#define MCDE_DITCTRLA_FOFFX_MASK 0x000003E0 +#define MCDE_DITCTRLA_FOFFX(__x) \ + MCDE_VAL2REG(MCDE_DITCTRLA, FOFFX, __x) +#define MCDE_DITCTRLA_FOFFY_SHIFT 10 +#define MCDE_DITCTRLA_FOFFY_MASK 0x00007C00 +#define MCDE_DITCTRLA_FOFFY(__x) \ + MCDE_VAL2REG(MCDE_DITCTRLA, FOFFY, __x) +#define MCDE_DITCTRLB 0x00000A64 +#define MCDE_DITCTRLB_TEMP_SHIFT 0 +#define MCDE_DITCTRLB_TEMP_MASK 0x00000001 +#define MCDE_DITCTRLB_TEMP(__x) \ + MCDE_VAL2REG(MCDE_DITCTRLB, TEMP, __x) +#define MCDE_DITCTRLB_COMP_SHIFT 1 +#define MCDE_DITCTRLB_COMP_MASK 0x00000002 +#define MCDE_DITCTRLB_COMP(__x) \ + MCDE_VAL2REG(MCDE_DITCTRLB, COMP, __x) +#define MCDE_DITCTRLB_MODE_SHIFT 2 +#define MCDE_DITCTRLB_MODE_MASK 0x0000000C +#define MCDE_DITCTRLB_MODE(__x) \ + MCDE_VAL2REG(MCDE_DITCTRLB, MODE, __x) +#define MCDE_DITCTRLB_MASK_SHIFT 4 +#define MCDE_DITCTRLB_MASK_MASK 0x00000010 +#define MCDE_DITCTRLB_MASK(__x) \ + MCDE_VAL2REG(MCDE_DITCTRLB, MASK, __x) +#define MCDE_DITCTRLB_FOFFX_SHIFT 5 +#define MCDE_DITCTRLB_FOFFX_MASK 0x000003E0 +#define MCDE_DITCTRLB_FOFFX(__x) \ + MCDE_VAL2REG(MCDE_DITCTRLB, FOFFX, __x) +#define MCDE_DITCTRLB_FOFFY_SHIFT 10 +#define MCDE_DITCTRLB_FOFFY_MASK 0x00007C00 +#define MCDE_DITCTRLB_FOFFY(__x) \ + MCDE_VAL2REG(MCDE_DITCTRLB, FOFFY, __x) +#define MCDE_DITOFFA 0x00000868 +#define MCDE_DITOFFA_GROUPOFFSET 0x200 +#define MCDE_DITOFFA_XG_SHIFT 0 +#define MCDE_DITOFFA_XG_MASK 0x0000001F +#define MCDE_DITOFFA_XG(__x) \ + MCDE_VAL2REG(MCDE_DITOFFA, XG, __x) +#define MCDE_DITOFFA_YG_SHIFT 8 +#define MCDE_DITOFFA_YG_MASK 0x00001F00 +#define MCDE_DITOFFA_YG(__x) \ + MCDE_VAL2REG(MCDE_DITOFFA, YG, __x) +#define MCDE_DITOFFA_XB_SHIFT 16 +#define MCDE_DITOFFA_XB_MASK 0x001F0000 +#define MCDE_DITOFFA_XB(__x) \ + MCDE_VAL2REG(MCDE_DITOFFA, XB, __x) +#define MCDE_DITOFFA_YB_SHIFT 24 +#define MCDE_DITOFFA_YB_MASK 0x1F000000 +#define MCDE_DITOFFA_YB(__x) \ + MCDE_VAL2REG(MCDE_DITOFFA, YB, __x) +#define MCDE_DITOFFB 0x00000A68 +#define MCDE_DITOFFB_XG_SHIFT 0 +#define MCDE_DITOFFB_XG_MASK 0x0000001F +#define MCDE_DITOFFB_XG(__x) \ + MCDE_VAL2REG(MCDE_DITOFFB, XG, __x) +#define MCDE_DITOFFB_YG_SHIFT 8 +#define MCDE_DITOFFB_YG_MASK 0x00001F00 +#define MCDE_DITOFFB_YG(__x) \ + MCDE_VAL2REG(MCDE_DITOFFB, YG, __x) +#define MCDE_DITOFFB_XB_SHIFT 16 +#define MCDE_DITOFFB_XB_MASK 0x001F0000 +#define MCDE_DITOFFB_XB(__x) \ + MCDE_VAL2REG(MCDE_DITOFFB, XB, __x) +#define MCDE_DITOFFB_YB_SHIFT 24 +#define MCDE_DITOFFB_YB_MASK 0x1F000000 +#define MCDE_DITOFFB_YB(__x) \ + MCDE_VAL2REG(MCDE_DITOFFB, YB, __x) +#define MCDE_PAL0A 0x0000086C +#define MCDE_PAL0A_GROUPOFFSET 0x200 +#define MCDE_PAL0A_BLUE_SHIFT 0 +#define MCDE_PAL0A_BLUE_MASK 0x00000FFF +#define MCDE_PAL0A_BLUE(__x) \ + MCDE_VAL2REG(MCDE_PAL0A, BLUE, __x) +#define MCDE_PAL0A_GREEN_SHIFT 16 +#define MCDE_PAL0A_GREEN_MASK 0x0FFF0000 +#define MCDE_PAL0A_GREEN(__x) \ + MCDE_VAL2REG(MCDE_PAL0A, GREEN, __x) +#define MCDE_PAL0B 0x00000A6C +#define MCDE_PAL0B_BLUE_SHIFT 0 +#define MCDE_PAL0B_BLUE_MASK 0x00000FFF +#define MCDE_PAL0B_BLUE(__x) \ + MCDE_VAL2REG(MCDE_PAL0B, BLUE, __x) +#define MCDE_PAL0B_GREEN_SHIFT 16 +#define MCDE_PAL0B_GREEN_MASK 0x0FFF0000 +#define MCDE_PAL0B_GREEN(__x) \ + MCDE_VAL2REG(MCDE_PAL0B, GREEN, __x) +#define MCDE_PAL1A 0x00000870 +#define MCDE_PAL1A_GROUPOFFSET 0x200 +#define MCDE_PAL1A_RED_SHIFT 0 +#define MCDE_PAL1A_RED_MASK 0x00000FFF +#define MCDE_PAL1A_RED(__x) \ + MCDE_VAL2REG(MCDE_PAL1A, RED, __x) +#define MCDE_PAL1B 0x00000A70 +#define MCDE_PAL1B_RED_SHIFT 0 +#define MCDE_PAL1B_RED_MASK 0x00000FFF +#define MCDE_PAL1B_RED(__x) \ + MCDE_VAL2REG(MCDE_PAL1B, RED, __x) +#define MCDE_ROTADD0A 0x00000874 +#define MCDE_ROTADD0A_GROUPOFFSET 0x200 +#define MCDE_ROTADD0A_ROTADD0_SHIFT 3 +#define MCDE_ROTADD0A_ROTADD0_MASK 0xFFFFFFF8 +#define MCDE_ROTADD0A_ROTADD0(__x) \ + MCDE_VAL2REG(MCDE_ROTADD0A, ROTADD0, __x) +#define MCDE_ROTADD0B 0x00000A74 +#define MCDE_ROTADD0B_ROTADD0_SHIFT 3 +#define MCDE_ROTADD0B_ROTADD0_MASK 0xFFFFFFF8 +#define MCDE_ROTADD0B_ROTADD0(__x) \ + MCDE_VAL2REG(MCDE_ROTADD0B, ROTADD0, __x) +#define MCDE_ROTADD1A 0x00000878 +#define MCDE_ROTADD1A_GROUPOFFSET 0x200 +#define MCDE_ROTADD1A_ROTADD1_SHIFT 3 +#define MCDE_ROTADD1A_ROTADD1_MASK 0xFFFFFFF8 +#define MCDE_ROTADD1A_ROTADD1(__x) \ + MCDE_VAL2REG(MCDE_ROTADD1A, ROTADD1, __x) +#define MCDE_ROTADD1B 0x00000A78 +#define MCDE_ROTADD1B_ROTADD1_SHIFT 3 +#define MCDE_ROTADD1B_ROTADD1_MASK 0xFFFFFFF8 +#define MCDE_ROTADD1B_ROTADD1(__x) \ + MCDE_VAL2REG(MCDE_ROTADD1B, ROTADD1, __x) +#define MCDE_ROTACONF 0x0000087C +#define MCDE_ROTACONF_GROUPOFFSET 0x200 +#define MCDE_ROTACONF_ROTBURSTSIZE_SHIFT 0 +#define MCDE_ROTACONF_ROTBURSTSIZE_MASK 0x00000007 +#define MCDE_ROTACONF_ROTBURSTSIZE_1W 0 +#define MCDE_ROTACONF_ROTBURSTSIZE_2W 1 +#define MCDE_ROTACONF_ROTBURSTSIZE_4W 2 +#define MCDE_ROTACONF_ROTBURSTSIZE_8W 3 +#define MCDE_ROTACONF_ROTBURSTSIZE_HW_1W 4 +#define MCDE_ROTACONF_ROTBURSTSIZE_HW_2W 5 +#define MCDE_ROTACONF_ROTBURSTSIZE_HW_4W 6 +#define MCDE_ROTACONF_ROTBURSTSIZE_HW_8W 7 +#define MCDE_ROTACONF_ROTBURSTSIZE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_ROTACONF, ROTBURSTSIZE, \ + MCDE_ROTACONF_ROTBURSTSIZE_##__x) +#define MCDE_ROTACONF_ROTBURSTSIZE(__x) \ + MCDE_VAL2REG(MCDE_ROTACONF, ROTBURSTSIZE, __x) +#define MCDE_ROTACONF_ROTDIR_SHIFT 3 +#define MCDE_ROTACONF_ROTDIR_MASK 0x00000008 +#define MCDE_ROTACONF_ROTDIR_CCW 0 +#define MCDE_ROTACONF_ROTDIR_CW 1 +#define MCDE_ROTACONF_ROTDIR_ENUM(__x) \ + MCDE_VAL2REG(MCDE_ROTACONF, ROTDIR, MCDE_ROTACONF_ROTDIR_##__x) +#define MCDE_ROTACONF_ROTDIR(__x) \ + MCDE_VAL2REG(MCDE_ROTACONF, ROTDIR, __x) +#define MCDE_ROTACONF_WR_MAXOUT_SHIFT 4 +#define MCDE_ROTACONF_WR_MAXOUT_MASK 0x00000030 +#define MCDE_ROTACONF_WR_MAXOUT_1_REQ 0 +#define MCDE_ROTACONF_WR_MAXOUT_2_REQ 1 +#define MCDE_ROTACONF_WR_MAXOUT_4_REQ 2 +#define MCDE_ROTACONF_WR_MAXOUT_8_REQ 3 +#define MCDE_ROTACONF_WR_MAXOUT_ENUM(__x) \ + MCDE_VAL2REG(MCDE_ROTACONF, WR_MAXOUT, MCDE_ROTACONF_WR_MAXOUT_##__x) +#define MCDE_ROTACONF_WR_MAXOUT(__x) \ + MCDE_VAL2REG(MCDE_ROTACONF, WR_MAXOUT, __x) +#define MCDE_ROTACONF_RD_MAXOUT_SHIFT 6 +#define MCDE_ROTACONF_RD_MAXOUT_MASK 0x000000C0 +#define MCDE_ROTACONF_RD_MAXOUT_1_REQ 0 +#define MCDE_ROTACONF_RD_MAXOUT_2_REQ 1 +#define MCDE_ROTACONF_RD_MAXOUT_4_REQ 2 +#define MCDE_ROTACONF_RD_MAXOUT_8_REQ 3 +#define MCDE_ROTACONF_RD_MAXOUT_ENUM(__x) \ + MCDE_VAL2REG(MCDE_ROTACONF, RD_MAXOUT, MCDE_ROTACONF_RD_MAXOUT_##__x) +#define MCDE_ROTACONF_RD_MAXOUT(__x) \ + MCDE_VAL2REG(MCDE_ROTACONF, RD_MAXOUT, __x) +#define MCDE_ROTACONF_STRIP_WIDTH_SHIFT 8 +#define MCDE_ROTACONF_STRIP_WIDTH_MASK 0x00007F00 +#define MCDE_ROTACONF_STRIP_WIDTH_2PIX 0 +#define MCDE_ROTACONF_STRIP_WIDTH_4PIX 1 +#define MCDE_ROTACONF_STRIP_WIDTH_8PIX 2 +#define MCDE_ROTACONF_STRIP_WIDTH_16PIX 3 +#define MCDE_ROTACONF_STRIP_WIDTH_32PIX 4 +#define MCDE_ROTACONF_STRIP_WIDTH_ENUM(__x) \ + MCDE_VAL2REG(MCDE_ROTACONF, STRIP_WIDTH, \ + MCDE_ROTACONF_STRIP_WIDTH_##__x) +#define MCDE_ROTACONF_STRIP_WIDTH(__x) \ + MCDE_VAL2REG(MCDE_ROTACONF, STRIP_WIDTH, __x) +#define MCDE_ROTACONF_SINGLE_BUF_SHIFT 15 +#define MCDE_ROTACONF_SINGLE_BUF_MASK 0x00008000 +#define MCDE_ROTACONF_SINGLE_BUF(__x) \ + MCDE_VAL2REG(MCDE_ROTACONF, SINGLE_BUF, __x) +#define MCDE_ROTACONF_WR_ROPC_SHIFT 16 +#define MCDE_ROTACONF_WR_ROPC_MASK 0x00FF0000 +#define MCDE_ROTACONF_WR_ROPC(__x) \ + MCDE_VAL2REG(MCDE_ROTACONF, WR_ROPC, __x) +#define MCDE_ROTACONF_RD_ROPC_SHIFT 24 +#define MCDE_ROTACONF_RD_ROPC_MASK 0xFF000000 +#define MCDE_ROTACONF_RD_ROPC(__x) \ + MCDE_VAL2REG(MCDE_ROTACONF, RD_ROPC, __x) +#define MCDE_ROTBCONF 0x00000A7C +#define MCDE_ROTBCONF_ROTBURSTSIZE_SHIFT 0 +#define MCDE_ROTBCONF_ROTBURSTSIZE_MASK 0x00000007 +#define MCDE_ROTBCONF_ROTBURSTSIZE_1W 0 +#define MCDE_ROTBCONF_ROTBURSTSIZE_2W 1 +#define MCDE_ROTBCONF_ROTBURSTSIZE_4W 2 +#define MCDE_ROTBCONF_ROTBURSTSIZE_8W 3 +#define MCDE_ROTBCONF_ROTBURSTSIZE_HW_1W 4 +#define MCDE_ROTBCONF_ROTBURSTSIZE_HW_2W 5 +#define MCDE_ROTBCONF_ROTBURSTSIZE_HW_4W 6 +#define MCDE_ROTBCONF_ROTBURSTSIZE_HW_8W 7 +#define MCDE_ROTBCONF_ROTBURSTSIZE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_ROTBCONF, ROTBURSTSIZE, \ + MCDE_ROTBCONF_ROTBURSTSIZE_##__x) +#define MCDE_ROTBCONF_ROTBURSTSIZE(__x) \ + MCDE_VAL2REG(MCDE_ROTBCONF, ROTBURSTSIZE, __x) +#define MCDE_ROTBCONF_ROTDIR_SHIFT 3 +#define MCDE_ROTBCONF_ROTDIR_MASK 0x00000008 +#define MCDE_ROTBCONF_ROTDIR_CCW 0 +#define MCDE_ROTBCONF_ROTDIR_CW 1 +#define MCDE_ROTBCONF_ROTDIR_ENUM(__x) \ + MCDE_VAL2REG(MCDE_ROTBCONF, ROTDIR, MCDE_ROTBCONF_ROTDIR_##__x) +#define MCDE_ROTBCONF_ROTDIR(__x) \ + MCDE_VAL2REG(MCDE_ROTBCONF, ROTDIR, __x) +#define MCDE_ROTBCONF_WR_MAXOUT_SHIFT 4 +#define MCDE_ROTBCONF_WR_MAXOUT_MASK 0x00000030 +#define MCDE_ROTBCONF_WR_MAXOUT_1_REQ 0 +#define MCDE_ROTBCONF_WR_MAXOUT_2_REQ 1 +#define MCDE_ROTBCONF_WR_MAXOUT_4_REQ 2 +#define MCDE_ROTBCONF_WR_MAXOUT_8_REQ 3 +#define MCDE_ROTBCONF_WR_MAXOUT_ENUM(__x) \ + MCDE_VAL2REG(MCDE_ROTBCONF, WR_MAXOUT, MCDE_ROTBCONF_WR_MAXOUT_##__x) +#define MCDE_ROTBCONF_WR_MAXOUT(__x) \ + MCDE_VAL2REG(MCDE_ROTBCONF, WR_MAXOUT, __x) +#define MCDE_ROTBCONF_RD_MAXOUT_SHIFT 6 +#define MCDE_ROTBCONF_RD_MAXOUT_MASK 0x000000C0 +#define MCDE_ROTBCONF_RD_MAXOUT_1_REQ 0 +#define MCDE_ROTBCONF_RD_MAXOUT_2_REQ 1 +#define MCDE_ROTBCONF_RD_MAXOUT_4_REQ 2 +#define MCDE_ROTBCONF_RD_MAXOUT_8_REQ 3 +#define MCDE_ROTBCONF_RD_MAXOUT_ENUM(__x) \ + MCDE_VAL2REG(MCDE_ROTBCONF, RD_MAXOUT, MCDE_ROTBCONF_RD_MAXOUT_##__x) +#define MCDE_ROTBCONF_RD_MAXOUT(__x) \ + MCDE_VAL2REG(MCDE_ROTBCONF, RD_MAXOUT, __x) +#define MCDE_ROTBCONF_STRIP_WIDTH_SHIFT 8 +#define MCDE_ROTBCONF_STRIP_WIDTH_MASK 0x00007F00 +#define MCDE_ROTBCONF_STRIP_WIDTH_2PIX 0 +#define MCDE_ROTBCONF_STRIP_WIDTH_4PIX 1 +#define MCDE_ROTBCONF_STRIP_WIDTH_8PIX 2 +#define MCDE_ROTBCONF_STRIP_WIDTH_16PIX 3 +#define MCDE_ROTBCONF_STRIP_WIDTH_32PIX 4 +#define MCDE_ROTBCONF_STRIP_WIDTH_ENUM(__x) \ + MCDE_VAL2REG(MCDE_ROTBCONF, STRIP_WIDTH, \ + MCDE_ROTBCONF_STRIP_WIDTH_##__x) +#define MCDE_ROTBCONF_STRIP_WIDTH(__x) \ + MCDE_VAL2REG(MCDE_ROTBCONF, STRIP_WIDTH, __x) +#define MCDE_ROTBCONF_SINGLE_BUF_SHIFT 15 +#define MCDE_ROTBCONF_SINGLE_BUF_MASK 0x00008000 +#define MCDE_ROTBCONF_SINGLE_BUF(__x) \ + MCDE_VAL2REG(MCDE_ROTBCONF, SINGLE_BUF, __x) +#define MCDE_ROTBCONF_WR_ROPC_SHIFT 16 +#define MCDE_ROTBCONF_WR_ROPC_MASK 0x00FF0000 +#define MCDE_ROTBCONF_WR_ROPC(__x) \ + MCDE_VAL2REG(MCDE_ROTBCONF, WR_ROPC, __x) +#define MCDE_ROTBCONF_RD_ROPC_SHIFT 24 +#define MCDE_ROTBCONF_RD_ROPC_MASK 0xFF000000 +#define MCDE_ROTBCONF_RD_ROPC(__x) \ + MCDE_VAL2REG(MCDE_ROTBCONF, RD_ROPC, __x) +#define MCDE_SYNCHCONFA 0x00000880 +#define MCDE_SYNCHCONFA_GROUPOFFSET 0x200 +#define MCDE_SYNCHCONFA_HWREQVEVENT_SHIFT 0 +#define MCDE_SYNCHCONFA_HWREQVEVENT_MASK 0x00000003 +#define MCDE_SYNCHCONFA_HWREQVEVENT_VSYNC 0 +#define MCDE_SYNCHCONFA_HWREQVEVENT_BACK_PORCH 1 +#define MCDE_SYNCHCONFA_HWREQVEVENT_ACTIVE_VIDEO 2 +#define MCDE_SYNCHCONFA_HWREQVEVENT_FRONT_PORCH 3 +#define MCDE_SYNCHCONFA_HWREQVEVENT_ENUM(__x) \ + MCDE_VAL2REG(MCDE_SYNCHCONFA, HWREQVEVENT, \ + MCDE_SYNCHCONFA_HWREQVEVENT_##__x) +#define MCDE_SYNCHCONFA_HWREQVEVENT(__x) \ + MCDE_VAL2REG(MCDE_SYNCHCONFA, HWREQVEVENT, __x) +#define MCDE_SYNCHCONFA_HWREQVCNT_SHIFT 2 +#define MCDE_SYNCHCONFA_HWREQVCNT_MASK 0x0000FFFC +#define MCDE_SYNCHCONFA_HWREQVCNT(__x) \ + MCDE_VAL2REG(MCDE_SYNCHCONFA, HWREQVCNT, __x) +#define MCDE_SYNCHCONFA_SWINTVEVENT_SHIFT 16 +#define MCDE_SYNCHCONFA_SWINTVEVENT_MASK 0x00030000 +#define MCDE_SYNCHCONFA_SWINTVEVENT_VSYNC 0 +#define MCDE_SYNCHCONFA_SWINTVEVENT_BACK_PORCH 1 +#define MCDE_SYNCHCONFA_SWINTVEVENT_ACTIVE_VIDEO 2 +#define MCDE_SYNCHCONFA_SWINTVEVENT_FRONT_PORCH 3 +#define MCDE_SYNCHCONFA_SWINTVEVENT_ENUM(__x) \ + MCDE_VAL2REG(MCDE_SYNCHCONFA, SWINTVEVENT, \ + MCDE_SYNCHCONFA_SWINTVEVENT_##__x) +#define MCDE_SYNCHCONFA_SWINTVEVENT(__x) \ + MCDE_VAL2REG(MCDE_SYNCHCONFA, SWINTVEVENT, __x) +#define MCDE_SYNCHCONFA_SWINTVCNT_SHIFT 18 +#define MCDE_SYNCHCONFA_SWINTVCNT_MASK 0xFFFC0000 +#define MCDE_SYNCHCONFA_SWINTVCNT(__x) \ + MCDE_VAL2REG(MCDE_SYNCHCONFA, SWINTVCNT, __x) +#define MCDE_SYNCHCONFB 0x00000A80 +#define MCDE_SYNCHCONFB_HWREQVEVENT_SHIFT 0 +#define MCDE_SYNCHCONFB_HWREQVEVENT_MASK 0x00000003 +#define MCDE_SYNCHCONFB_HWREQVEVENT_VSYNC 0 +#define MCDE_SYNCHCONFB_HWREQVEVENT_BACK_PORCH 1 +#define MCDE_SYNCHCONFB_HWREQVEVENT_ACTIVE_VIDEO 2 +#define MCDE_SYNCHCONFB_HWREQVEVENT_FRONT_PORCH 3 +#define MCDE_SYNCHCONFB_HWREQVEVENT_ENUM(__x) \ + MCDE_VAL2REG(MCDE_SYNCHCONFB, HWREQVEVENT, \ + MCDE_SYNCHCONFB_HWREQVEVENT_##__x) +#define MCDE_SYNCHCONFB_HWREQVEVENT(__x) \ + MCDE_VAL2REG(MCDE_SYNCHCONFB, HWREQVEVENT, __x) +#define MCDE_SYNCHCONFB_HWREQVCNT_SHIFT 2 +#define MCDE_SYNCHCONFB_HWREQVCNT_MASK 0x0000FFFC +#define MCDE_SYNCHCONFB_HWREQVCNT(__x) \ + MCDE_VAL2REG(MCDE_SYNCHCONFB, HWREQVCNT, __x) +#define MCDE_SYNCHCONFB_SWINTVEVENT_SHIFT 16 +#define MCDE_SYNCHCONFB_SWINTVEVENT_MASK 0x00030000 +#define MCDE_SYNCHCONFB_SWINTVEVENT_VSYNC 0 +#define MCDE_SYNCHCONFB_SWINTVEVENT_BACK_PORCH 1 +#define MCDE_SYNCHCONFB_SWINTVEVENT_ACTIVE_VIDEO 2 +#define MCDE_SYNCHCONFB_SWINTVEVENT_FRONT_PORCH 3 +#define MCDE_SYNCHCONFB_SWINTVEVENT_ENUM(__x) \ + MCDE_VAL2REG(MCDE_SYNCHCONFB, SWINTVEVENT, \ + MCDE_SYNCHCONFB_SWINTVEVENT_##__x) +#define MCDE_SYNCHCONFB_SWINTVEVENT(__x) \ + MCDE_VAL2REG(MCDE_SYNCHCONFB, SWINTVEVENT, __x) +#define MCDE_SYNCHCONFB_SWINTVCNT_SHIFT 18 +#define MCDE_SYNCHCONFB_SWINTVCNT_MASK 0xFFFC0000 +#define MCDE_SYNCHCONFB_SWINTVCNT(__x) \ + MCDE_VAL2REG(MCDE_SYNCHCONFB, SWINTVCNT, __x) +#define MCDE_CTRLA 0x00000884 +#define MCDE_CTRLA_GROUPOFFSET 0x200 +#define MCDE_CTRLA_FIFOWTRMRK_SHIFT 0 +#define MCDE_CTRLA_FIFOWTRMRK_MASK 0x000003FF +#define MCDE_CTRLA_FIFOWTRMRK(__x) \ + MCDE_VAL2REG(MCDE_CTRLA, FIFOWTRMRK, __x) +#define MCDE_CTRLA_FIFOEMPTY_SHIFT 12 +#define MCDE_CTRLA_FIFOEMPTY_MASK 0x00001000 +#define MCDE_CTRLA_FIFOEMPTY(__x) \ + MCDE_VAL2REG(MCDE_CTRLA, FIFOEMPTY, __x) +#define MCDE_CTRLA_FIFOFULL_SHIFT 13 +#define MCDE_CTRLA_FIFOFULL_MASK 0x00002000 +#define MCDE_CTRLA_FIFOFULL(__x) \ + MCDE_VAL2REG(MCDE_CTRLA, FIFOFULL, __x) +#define MCDE_CTRLA_FORMID_SHIFT 16 +#define MCDE_CTRLA_FORMID_MASK 0x00070000 +#define MCDE_CTRLA_FORMID_DSI0VID 0 +#define MCDE_CTRLA_FORMID_DSI0CMD 1 +#define MCDE_CTRLA_FORMID_DSI1VID 2 +#define MCDE_CTRLA_FORMID_DSI1CMD 3 +#define MCDE_CTRLA_FORMID_DSI2VID 4 +#define MCDE_CTRLA_FORMID_DSI2CMD 5 +#define MCDE_CTRLA_FORMID_DPIA 0 +#define MCDE_CTRLA_FORMID_DPIB 1 +#define MCDE_CTRLA_FORMID_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CTRLA, FORMID, MCDE_CTRLA_FORMID_##__x) +#define MCDE_CTRLA_FORMID(__x) \ + MCDE_VAL2REG(MCDE_CTRLA, FORMID, __x) +#define MCDE_CTRLA_FORMTYPE_SHIFT 20 +#define MCDE_CTRLA_FORMTYPE_MASK 0x00700000 +#define MCDE_CTRLA_FORMTYPE_DPITV 0 +#define MCDE_CTRLA_FORMTYPE_DBI 1 +#define MCDE_CTRLA_FORMTYPE_DSI 2 +#define MCDE_CTRLA_FORMTYPE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CTRLA, FORMTYPE, MCDE_CTRLA_FORMTYPE_##__x) +#define MCDE_CTRLA_FORMTYPE(__x) \ + MCDE_VAL2REG(MCDE_CTRLA, FORMTYPE, __x) +#define MCDE_CTRLB 0x00000A84 +#define MCDE_CTRLB_FIFOWTRMRK_SHIFT 0 +#define MCDE_CTRLB_FIFOWTRMRK_MASK 0x000003FF +#define MCDE_CTRLB_FIFOWTRMRK(__x) \ + MCDE_VAL2REG(MCDE_CTRLB, FIFOWTRMRK, __x) +#define MCDE_CTRLB_FIFOEMPTY_SHIFT 12 +#define MCDE_CTRLB_FIFOEMPTY_MASK 0x00001000 +#define MCDE_CTRLB_FIFOEMPTY(__x) \ + MCDE_VAL2REG(MCDE_CTRLB, FIFOEMPTY, __x) +#define MCDE_CTRLB_FIFOFULL_SHIFT 13 +#define MCDE_CTRLB_FIFOFULL_MASK 0x00002000 +#define MCDE_CTRLB_FIFOFULL(__x) \ + MCDE_VAL2REG(MCDE_CTRLB, FIFOFULL, __x) +#define MCDE_CTRLB_FORMID_SHIFT 16 +#define MCDE_CTRLB_FORMID_MASK 0x00070000 +#define MCDE_CTRLB_FORMID_DSI0VID 0 +#define MCDE_CTRLB_FORMID_DSI0CMD 1 +#define MCDE_CTRLB_FORMID_DSI1VID 2 +#define MCDE_CTRLB_FORMID_DSI1CMD 3 +#define MCDE_CTRLB_FORMID_DSI2VID 4 +#define MCDE_CTRLB_FORMID_DSI2CMD 5 +#define MCDE_CTRLB_FORMID_DPIA 0 +#define MCDE_CTRLB_FORMID_DPIB 1 +#define MCDE_CTRLB_FORMID_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CTRLB, FORMID, MCDE_CTRLB_FORMID_##__x) +#define MCDE_CTRLB_FORMID(__x) \ + MCDE_VAL2REG(MCDE_CTRLB, FORMID, __x) +#define MCDE_CTRLB_FORMTYPE_SHIFT 20 +#define MCDE_CTRLB_FORMTYPE_MASK 0x00700000 +#define MCDE_CTRLB_FORMTYPE_DPITV 0 +#define MCDE_CTRLB_FORMTYPE_DBI 1 +#define MCDE_CTRLB_FORMTYPE_DSI 2 +#define MCDE_CTRLB_FORMTYPE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CTRLB, FORMTYPE, MCDE_CTRLB_FORMTYPE_##__x) +#define MCDE_CTRLB_FORMTYPE(__x) \ + MCDE_VAL2REG(MCDE_CTRLB, FORMTYPE, __x) +#define MCDE_GAM0A 0x00000888 +#define MCDE_GAM0A_GROUPOFFSET 0x200 +#define MCDE_GAM0A_BLUE_SHIFT 0 +#define MCDE_GAM0A_BLUE_MASK 0x00FFFFFF +#define MCDE_GAM0A_BLUE(__x) \ + MCDE_VAL2REG(MCDE_GAM0A, BLUE, __x) +#define MCDE_GAM0B 0x00000A88 +#define MCDE_GAM0B_BLUE_SHIFT 0 +#define MCDE_GAM0B_BLUE_MASK 0x00FFFFFF +#define MCDE_GAM0B_BLUE(__x) \ + MCDE_VAL2REG(MCDE_GAM0B, BLUE, __x) +#define MCDE_GAM1A 0x0000088C +#define MCDE_GAM1A_GROUPOFFSET 0x200 +#define MCDE_GAM1A_GREEN_SHIFT 0 +#define MCDE_GAM1A_GREEN_MASK 0x00FFFFFF +#define MCDE_GAM1A_GREEN(__x) \ + MCDE_VAL2REG(MCDE_GAM1A, GREEN, __x) +#define MCDE_GAM1B 0x00000A8C +#define MCDE_GAM1B_GREEN_SHIFT 0 +#define MCDE_GAM1B_GREEN_MASK 0x00FFFFFF +#define MCDE_GAM1B_GREEN(__x) \ + MCDE_VAL2REG(MCDE_GAM1B, GREEN, __x) +#define MCDE_GAM2A 0x00000890 +#define MCDE_GAM2A_GROUPOFFSET 0x200 +#define MCDE_GAM2A_RED_SHIFT 0 +#define MCDE_GAM2A_RED_MASK 0x00FFFFFF +#define MCDE_GAM2A_RED(__x) \ + MCDE_VAL2REG(MCDE_GAM2A, RED, __x) +#define MCDE_GAM2B 0x00000A90 +#define MCDE_GAM2B_RED_SHIFT 0 +#define MCDE_GAM2B_RED_MASK 0x00FFFFFF +#define MCDE_GAM2B_RED(__x) \ + MCDE_VAL2REG(MCDE_GAM2B, RED, __x) +#define MCDE_OLEDCONV1A 0x00000894 +#define MCDE_OLEDCONV1A_GROUPOFFSET 0x200 +#define MCDE_OLEDCONV1A_ALPHA_RED_SHIFT 0 +#define MCDE_OLEDCONV1A_ALPHA_RED_MASK 0x00003FFF +#define MCDE_OLEDCONV1A_ALPHA_RED(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV1A, ALPHA_RED, __x) +#define MCDE_OLEDCONV1A_ALPHA_GREEN_SHIFT 16 +#define MCDE_OLEDCONV1A_ALPHA_GREEN_MASK 0x3FFF0000 +#define MCDE_OLEDCONV1A_ALPHA_GREEN(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV1A, ALPHA_GREEN, __x) +#define MCDE_OLEDCONV1B 0x00000A94 +#define MCDE_OLEDCONV1B_ALPHA_RED_SHIFT 0 +#define MCDE_OLEDCONV1B_ALPHA_RED_MASK 0x00003FFF +#define MCDE_OLEDCONV1B_ALPHA_RED(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV1B, ALPHA_RED, __x) +#define MCDE_OLEDCONV1B_ALPHA_GREEN_SHIFT 16 +#define MCDE_OLEDCONV1B_ALPHA_GREEN_MASK 0x3FFF0000 +#define MCDE_OLEDCONV1B_ALPHA_GREEN(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV1B, ALPHA_GREEN, __x) +#define MCDE_OLEDCONV2A 0x00000898 +#define MCDE_OLEDCONV2A_GROUPOFFSET 0x200 +#define MCDE_OLEDCONV2A_ALPHA_BLUE_SHIFT 0 +#define MCDE_OLEDCONV2A_ALPHA_BLUE_MASK 0x00003FFF +#define MCDE_OLEDCONV2A_ALPHA_BLUE(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV2A, ALPHA_BLUE, __x) +#define MCDE_OLEDCONV2A_BETA_RED_SHIFT 16 +#define MCDE_OLEDCONV2A_BETA_RED_MASK 0x3FFF0000 +#define MCDE_OLEDCONV2A_BETA_RED(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV2A, BETA_RED, __x) +#define MCDE_OLEDCONV2B 0x00000A98 +#define MCDE_OLEDCONV2B_ALPHA_BLUE_SHIFT 0 +#define MCDE_OLEDCONV2B_ALPHA_BLUE_MASK 0x00003FFF +#define MCDE_OLEDCONV2B_ALPHA_BLUE(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV2B, ALPHA_BLUE, __x) +#define MCDE_OLEDCONV2B_BETA_RED_SHIFT 16 +#define MCDE_OLEDCONV2B_BETA_RED_MASK 0x3FFF0000 +#define MCDE_OLEDCONV2B_BETA_RED(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV2B, BETA_RED, __x) +#define MCDE_OLEDCONV3A 0x0000089C +#define MCDE_OLEDCONV3A_GROUPOFFSET 0x200 +#define MCDE_OLEDCONV3A_BETA_GREEN_SHIFT 0 +#define MCDE_OLEDCONV3A_BETA_GREEN_MASK 0x00003FFF +#define MCDE_OLEDCONV3A_BETA_GREEN(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV3A, BETA_GREEN, __x) +#define MCDE_OLEDCONV3A_BETA_BLUE_SHIFT 16 +#define MCDE_OLEDCONV3A_BETA_BLUE_MASK 0x3FFF0000 +#define MCDE_OLEDCONV3A_BETA_BLUE(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV3A, BETA_BLUE, __x) +#define MCDE_OLEDCONV3B 0x00000A9C +#define MCDE_OLEDCONV3B_BETA_GREEN_SHIFT 0 +#define MCDE_OLEDCONV3B_BETA_GREEN_MASK 0x00003FFF +#define MCDE_OLEDCONV3B_BETA_GREEN(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV3B, BETA_GREEN, __x) +#define MCDE_OLEDCONV3B_BETA_BLUE_SHIFT 16 +#define MCDE_OLEDCONV3B_BETA_BLUE_MASK 0x3FFF0000 +#define MCDE_OLEDCONV3B_BETA_BLUE(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV3B, BETA_BLUE, __x) +#define MCDE_OLEDCONV4A 0x000008A0 +#define MCDE_OLEDCONV4A_GROUPOFFSET 0x200 +#define MCDE_OLEDCONV4A_GAMMA_RED_SHIFT 0 +#define MCDE_OLEDCONV4A_GAMMA_RED_MASK 0x00003FFF +#define MCDE_OLEDCONV4A_GAMMA_RED(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV4A, GAMMA_RED, __x) +#define MCDE_OLEDCONV4A_GAMMA_GREEN_SHIFT 16 +#define MCDE_OLEDCONV4A_GAMMA_GREEN_MASK 0x3FFF0000 +#define MCDE_OLEDCONV4A_GAMMA_GREEN(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV4A, GAMMA_GREEN, __x) +#define MCDE_OLEDCONV4B 0x00000AA0 +#define MCDE_OLEDCONV4B_GAMMA_RED_SHIFT 0 +#define MCDE_OLEDCONV4B_GAMMA_RED_MASK 0x00003FFF +#define MCDE_OLEDCONV4B_GAMMA_RED(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV4B, GAMMA_RED, __x) +#define MCDE_OLEDCONV4B_GAMMA_GREEN_SHIFT 16 +#define MCDE_OLEDCONV4B_GAMMA_GREEN_MASK 0x3FFF0000 +#define MCDE_OLEDCONV4B_GAMMA_GREEN(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV4B, GAMMA_GREEN, __x) +#define MCDE_OLEDCONV5A 0x000008A4 +#define MCDE_OLEDCONV5A_GROUPOFFSET 0x200 +#define MCDE_OLEDCONV5A_GAMMA_BLUE_SHIFT 0 +#define MCDE_OLEDCONV5A_GAMMA_BLUE_MASK 0x00003FFF +#define MCDE_OLEDCONV5A_GAMMA_BLUE(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV5A, GAMMA_BLUE, __x) +#define MCDE_OLEDCONV5A_OFF_RED_SHIFT 16 +#define MCDE_OLEDCONV5A_OFF_RED_MASK 0x3FFF0000 +#define MCDE_OLEDCONV5A_OFF_RED(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV5A, OFF_RED, __x) +#define MCDE_OLEDCONV5B 0x00000AA4 +#define MCDE_OLEDCONV5B_GAMMA_BLUE_SHIFT 0 +#define MCDE_OLEDCONV5B_GAMMA_BLUE_MASK 0x00003FFF +#define MCDE_OLEDCONV5B_GAMMA_BLUE(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV5B, GAMMA_BLUE, __x) +#define MCDE_OLEDCONV5B_OFF_RED_SHIFT 16 +#define MCDE_OLEDCONV5B_OFF_RED_MASK 0x3FFF0000 +#define MCDE_OLEDCONV5B_OFF_RED(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV5B, OFF_RED, __x) +#define MCDE_OLEDCONV6A 0x000008A8 +#define MCDE_OLEDCONV6A_GROUPOFFSET 0x200 +#define MCDE_OLEDCONV6A_OFF_GREEN_SHIFT 0 +#define MCDE_OLEDCONV6A_OFF_GREEN_MASK 0x00003FFF +#define MCDE_OLEDCONV6A_OFF_GREEN(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV6A, OFF_GREEN, __x) +#define MCDE_OLEDCONV6A_OFF_BLUE_SHIFT 16 +#define MCDE_OLEDCONV6A_OFF_BLUE_MASK 0x3FFF0000 +#define MCDE_OLEDCONV6A_OFF_BLUE(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV6A, OFF_BLUE, __x) +#define MCDE_OLEDCONV6B 0x00000AA8 +#define MCDE_OLEDCONV6B_OFF_GREEN_SHIFT 0 +#define MCDE_OLEDCONV6B_OFF_GREEN_MASK 0x00003FFF +#define MCDE_OLEDCONV6B_OFF_GREEN(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV6B, OFF_GREEN, __x) +#define MCDE_OLEDCONV6B_OFF_BLUE_SHIFT 16 +#define MCDE_OLEDCONV6B_OFF_BLUE_MASK 0x3FFF0000 +#define MCDE_OLEDCONV6B_OFF_BLUE(__x) \ + MCDE_VAL2REG(MCDE_OLEDCONV6B, OFF_BLUE, __x) +#define MCDE_CRC 0x00000C00 +#define MCDE_CRC_C1EN_SHIFT 2 +#define MCDE_CRC_C1EN_MASK 0x00000004 +#define MCDE_CRC_C1EN(__x) \ + MCDE_VAL2REG(MCDE_CRC, C1EN, __x) +#define MCDE_CRC_C2EN_SHIFT 3 +#define MCDE_CRC_C2EN_MASK 0x00000008 +#define MCDE_CRC_C2EN(__x) \ + MCDE_VAL2REG(MCDE_CRC, C2EN, __x) +#define MCDE_CRC_SYCEN0_SHIFT 7 +#define MCDE_CRC_SYCEN0_MASK 0x00000080 +#define MCDE_CRC_SYCEN0(__x) \ + MCDE_VAL2REG(MCDE_CRC, SYCEN0, __x) +#define MCDE_CRC_SYCEN1_SHIFT 8 +#define MCDE_CRC_SYCEN1_MASK 0x00000100 +#define MCDE_CRC_SYCEN1(__x) \ + MCDE_VAL2REG(MCDE_CRC, SYCEN1, __x) +#define MCDE_CRC_SIZE1_SHIFT 9 +#define MCDE_CRC_SIZE1_MASK 0x00000200 +#define MCDE_CRC_SIZE1(__x) \ + MCDE_VAL2REG(MCDE_CRC, SIZE1, __x) +#define MCDE_CRC_SIZE2_SHIFT 10 +#define MCDE_CRC_SIZE2_MASK 0x00000400 +#define MCDE_CRC_SIZE2(__x) \ + MCDE_VAL2REG(MCDE_CRC, SIZE2, __x) +#define MCDE_CRC_YUVCONVC1EN_SHIFT 15 +#define MCDE_CRC_YUVCONVC1EN_MASK 0x00008000 +#define MCDE_CRC_YUVCONVC1EN(__x) \ + MCDE_VAL2REG(MCDE_CRC, YUVCONVC1EN, __x) +#define MCDE_CRC_CS1EN_SHIFT 16 +#define MCDE_CRC_CS1EN_MASK 0x00010000 +#define MCDE_CRC_CS1EN(__x) \ + MCDE_VAL2REG(MCDE_CRC, CS1EN, __x) +#define MCDE_CRC_CS2EN_SHIFT 17 +#define MCDE_CRC_CS2EN_MASK 0x00020000 +#define MCDE_CRC_CS2EN(__x) \ + MCDE_VAL2REG(MCDE_CRC, CS2EN, __x) +#define MCDE_CRC_CS1POL_SHIFT 19 +#define MCDE_CRC_CS1POL_MASK 0x00080000 +#define MCDE_CRC_CS1POL(__x) \ + MCDE_VAL2REG(MCDE_CRC, CS1POL, __x) +#define MCDE_CRC_CS2POL_SHIFT 20 +#define MCDE_CRC_CS2POL_MASK 0x00100000 +#define MCDE_CRC_CS2POL(__x) \ + MCDE_VAL2REG(MCDE_CRC, CS2POL, __x) +#define MCDE_CRC_CD1POL_SHIFT 21 +#define MCDE_CRC_CD1POL_MASK 0x00200000 +#define MCDE_CRC_CD1POL(__x) \ + MCDE_VAL2REG(MCDE_CRC, CD1POL, __x) +#define MCDE_CRC_CD2POL_SHIFT 22 +#define MCDE_CRC_CD2POL_MASK 0x00400000 +#define MCDE_CRC_CD2POL(__x) \ + MCDE_VAL2REG(MCDE_CRC, CD2POL, __x) +#define MCDE_CRC_WR1POL_SHIFT 23 +#define MCDE_CRC_WR1POL_MASK 0x00800000 +#define MCDE_CRC_WR1POL(__x) \ + MCDE_VAL2REG(MCDE_CRC, WR1POL, __x) +#define MCDE_CRC_WR2POL_SHIFT 24 +#define MCDE_CRC_WR2POL_MASK 0x01000000 +#define MCDE_CRC_WR2POL(__x) \ + MCDE_VAL2REG(MCDE_CRC, WR2POL, __x) +#define MCDE_CRC_RD1POL_SHIFT 25 +#define MCDE_CRC_RD1POL_MASK 0x02000000 +#define MCDE_CRC_RD1POL(__x) \ + MCDE_VAL2REG(MCDE_CRC, RD1POL, __x) +#define MCDE_CRC_RD2POL_SHIFT 26 +#define MCDE_CRC_RD2POL_MASK 0x04000000 +#define MCDE_CRC_RD2POL(__x) \ + MCDE_VAL2REG(MCDE_CRC, RD2POL, __x) +#define MCDE_CRC_SYNCCTRL_SHIFT 29 +#define MCDE_CRC_SYNCCTRL_MASK 0x60000000 +#define MCDE_CRC_SYNCCTRL_NO_SYNC 0 +#define MCDE_CRC_SYNCCTRL_DBI0 1 +#define MCDE_CRC_SYNCCTRL_DBI1 2 +#define MCDE_CRC_SYNCCTRL_PING_PONG 3 +#define MCDE_CRC_SYNCCTRL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CRC, SYNCCTRL, MCDE_CRC_SYNCCTRL_##__x) +#define MCDE_CRC_SYNCCTRL(__x) \ + MCDE_VAL2REG(MCDE_CRC, SYNCCTRL, __x) +#define MCDE_CRC_CLAMPC1EN_SHIFT 31 +#define MCDE_CRC_CLAMPC1EN_MASK 0x80000000 +#define MCDE_CRC_CLAMPC1EN(__x) \ + MCDE_VAL2REG(MCDE_CRC, CLAMPC1EN, __x) +#define MCDE_PBCCRC0 0x00000C04 +#define MCDE_PBCCRC0_GROUPOFFSET 0x4 +#define MCDE_PBCCRC0_BSCM_SHIFT 0 +#define MCDE_PBCCRC0_BSCM_MASK 0x00000007 +#define MCDE_PBCCRC0_BSCM_1_8BIT 0 +#define MCDE_PBCCRC0_BSCM_2_8BIT 1 +#define MCDE_PBCCRC0_BSCM_3_8BIT 2 +#define MCDE_PBCCRC0_BSCM_1_16BIT 3 +#define MCDE_PBCCRC0_BSCM_2_16BIT 4 +#define MCDE_PBCCRC0_BSCM_ENUM(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC0, BSCM, MCDE_PBCCRC0_BSCM_##__x) +#define MCDE_PBCCRC0_BSCM(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC0, BSCM, __x) +#define MCDE_PBCCRC0_BSDM_SHIFT 3 +#define MCDE_PBCCRC0_BSDM_MASK 0x00000038 +#define MCDE_PBCCRC0_BSDM_1_8BIT 0 +#define MCDE_PBCCRC0_BSDM_2_8BIT 1 +#define MCDE_PBCCRC0_BSDM_3_8BIT 2 +#define MCDE_PBCCRC0_BSDM_1_16BIT 3 +#define MCDE_PBCCRC0_BSDM_2_16BIT 4 +#define MCDE_PBCCRC0_BSDM_ENUM(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC0, BSDM, MCDE_PBCCRC0_BSDM_##__x) +#define MCDE_PBCCRC0_BSDM(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC0, BSDM, __x) +#define MCDE_PBCCRC0_PDM_SHIFT 6 +#define MCDE_PBCCRC0_PDM_MASK 0x000000C0 +#define MCDE_PBCCRC0_PDM_NORMAL 0 +#define MCDE_PBCCRC0_PDM_16_TO_32 1 +#define MCDE_PBCCRC0_PDM_24_TO_32_RIGHT 2 +#define MCDE_PBCCRC0_PDM_24_TO_32_LEFT 3 +#define MCDE_PBCCRC0_PDM_ENUM(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC0, PDM, MCDE_PBCCRC0_PDM_##__x) +#define MCDE_PBCCRC0_PDM(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC0, PDM, __x) +#define MCDE_PBCCRC0_PDCTRL_SHIFT 12 +#define MCDE_PBCCRC0_PDCTRL_MASK 0x00001000 +#define MCDE_PBCCRC0_PDCTRL(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC0, PDCTRL, __x) +#define MCDE_PBCCRC0_BPP_SHIFT 13 +#define MCDE_PBCCRC0_BPP_MASK 0x0000E000 +#define MCDE_PBCCRC0_BPP_8BPP 0 +#define MCDE_PBCCRC0_BPP_12BPP 1 +#define MCDE_PBCCRC0_BPP_15BPP 2 +#define MCDE_PBCCRC0_BPP_16BPP 3 +#define MCDE_PBCCRC0_BPP_18BPP 4 +#define MCDE_PBCCRC0_BPP_24BPP 5 +#define MCDE_PBCCRC0_BPP(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC0, BPP, __x) +#define MCDE_PBCCRC1 0x00000C08 +#define MCDE_PBCCRC1_BSCM_SHIFT 0 +#define MCDE_PBCCRC1_BSCM_MASK 0x00000007 +#define MCDE_PBCCRC1_BSCM_1_8BIT 0 +#define MCDE_PBCCRC1_BSCM_2_8BIT 1 +#define MCDE_PBCCRC1_BSCM_3_8BIT 2 +#define MCDE_PBCCRC1_BSCM_1_16BIT 3 +#define MCDE_PBCCRC1_BSCM_2_16BIT 4 +#define MCDE_PBCCRC1_BSCM_ENUM(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC1, BSCM, MCDE_PBCCRC1_BSCM_##__x) +#define MCDE_PBCCRC1_BSCM(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC1, BSCM, __x) +#define MCDE_PBCCRC1_BSDM_SHIFT 3 +#define MCDE_PBCCRC1_BSDM_MASK 0x00000038 +#define MCDE_PBCCRC1_BSDM_1_8BIT 0 +#define MCDE_PBCCRC1_BSDM_2_8BIT 1 +#define MCDE_PBCCRC1_BSDM_3_8BIT 2 +#define MCDE_PBCCRC1_BSDM_1_16BIT 3 +#define MCDE_PBCCRC1_BSDM_2_16BIT 4 +#define MCDE_PBCCRC1_BSDM_ENUM(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC1, BSDM, MCDE_PBCCRC1_BSDM_##__x) +#define MCDE_PBCCRC1_BSDM(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC1, BSDM, __x) +#define MCDE_PBCCRC1_PDM_SHIFT 6 +#define MCDE_PBCCRC1_PDM_MASK 0x000000C0 +#define MCDE_PBCCRC1_PDM_NORMAL 0 +#define MCDE_PBCCRC1_PDM_16_TO_32 1 +#define MCDE_PBCCRC1_PDM_24_TO_32_RIGHT 2 +#define MCDE_PBCCRC1_PDM_24_TO_32_LEFT 3 +#define MCDE_PBCCRC1_PDM_ENUM(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC1, PDM, MCDE_PBCCRC1_PDM_##__x) +#define MCDE_PBCCRC1_PDM(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC1, PDM, __x) +#define MCDE_PBCCRC1_PDCTRL_SHIFT 12 +#define MCDE_PBCCRC1_PDCTRL_MASK 0x00001000 +#define MCDE_PBCCRC1_PDCTRL(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC1, PDCTRL, __x) +#define MCDE_PBCCRC1_BPP_SHIFT 13 +#define MCDE_PBCCRC1_BPP_MASK 0x0000E000 +#define MCDE_PBCCRC1_BPP_8BPP 0 +#define MCDE_PBCCRC1_BPP_12BPP 1 +#define MCDE_PBCCRC1_BPP_15BPP 2 +#define MCDE_PBCCRC1_BPP_16BPP 3 +#define MCDE_PBCCRC1_BPP_18BPP 4 +#define MCDE_PBCCRC1_BPP_24BPP 5 +#define MCDE_PBCCRC1_BPP(__x) \ + MCDE_VAL2REG(MCDE_PBCCRC1, BPP, __x) +#define MCDE_PBCBMRC00 0x00000C0C +#define MCDE_PBCBMRC00_GROUPOFFSET 0x4 +#define MCDE_PBCBMRC00_MUXI_SHIFT 0 +#define MCDE_PBCBMRC00_MUXI_MASK 0xFFFFFFFF +#define MCDE_PBCBMRC00_MUXI(__x) \ + MCDE_VAL2REG(MCDE_PBCBMRC00, MUXI, __x) +#define MCDE_PBCBMRC01 0x00000C10 +#define MCDE_PBCBMRC01_MUXI_SHIFT 0 +#define MCDE_PBCBMRC01_MUXI_MASK 0xFFFFFFFF +#define MCDE_PBCBMRC01_MUXI(__x) \ + MCDE_VAL2REG(MCDE_PBCBMRC01, MUXI, __x) +#define MCDE_PBCBMRC02 0x00000C14 +#define MCDE_PBCBMRC02_MUXI_SHIFT 0 +#define MCDE_PBCBMRC02_MUXI_MASK 0xFFFFFFFF +#define MCDE_PBCBMRC02_MUXI(__x) \ + MCDE_VAL2REG(MCDE_PBCBMRC02, MUXI, __x) +#define MCDE_PBCBMRC03 0x00000C18 +#define MCDE_PBCBMRC03_MUXI_SHIFT 0 +#define MCDE_PBCBMRC03_MUXI_MASK 0xFFFFFFFF +#define MCDE_PBCBMRC03_MUXI(__x) \ + MCDE_VAL2REG(MCDE_PBCBMRC03, MUXI, __x) +#define MCDE_PBCBMRC04 0x00000C1C +#define MCDE_PBCBMRC04_MUXI_SHIFT 0 +#define MCDE_PBCBMRC04_MUXI_MASK 0xFFFFFFFF +#define MCDE_PBCBMRC04_MUXI(__x) \ + MCDE_VAL2REG(MCDE_PBCBMRC04, MUXI, __x) +#define MCDE_PBCBMRC10 0x00000C20 +#define MCDE_PBCBMRC10_MUXI_SHIFT 0 +#define MCDE_PBCBMRC10_MUXI_MASK 0xFFFFFFFF +#define MCDE_PBCBMRC10_MUXI(__x) \ + MCDE_VAL2REG(MCDE_PBCBMRC10, MUXI, __x) +#define MCDE_PBCBMRC11 0x00000C24 +#define MCDE_PBCBMRC11_MUXI_SHIFT 0 +#define MCDE_PBCBMRC11_MUXI_MASK 0xFFFFFFFF +#define MCDE_PBCBMRC11_MUXI(__x) \ + MCDE_VAL2REG(MCDE_PBCBMRC11, MUXI, __x) +#define MCDE_PBCBMRC12 0x00000C28 +#define MCDE_PBCBMRC12_MUXI_SHIFT 0 +#define MCDE_PBCBMRC12_MUXI_MASK 0xFFFFFFFF +#define MCDE_PBCBMRC12_MUXI(__x) \ + MCDE_VAL2REG(MCDE_PBCBMRC12, MUXI, __x) +#define MCDE_PBCBMRC13 0x00000C2C +#define MCDE_PBCBMRC13_MUXI_SHIFT 0 +#define MCDE_PBCBMRC13_MUXI_MASK 0xFFFFFFFF +#define MCDE_PBCBMRC13_MUXI(__x) \ + MCDE_VAL2REG(MCDE_PBCBMRC13, MUXI, __x) +#define MCDE_PBCBMRC14 0x00000C30 +#define MCDE_PBCBMRC14_MUXI_SHIFT 0 +#define MCDE_PBCBMRC14_MUXI_MASK 0xFFFFFFFF +#define MCDE_PBCBMRC14_MUXI(__x) \ + MCDE_VAL2REG(MCDE_PBCBMRC14, MUXI, __x) +#define MCDE_PBCBCRC00 0x00000C34 +#define MCDE_PBCBCRC00_GROUPOFFSET 0x4 +#define MCDE_PBCBCRC00_CTLI_SHIFT 0 +#define MCDE_PBCBCRC00_CTLI_MASK 0xFFFFFFFF +#define MCDE_PBCBCRC00_CTLI(__x) \ + MCDE_VAL2REG(MCDE_PBCBCRC00, CTLI, __x) +#define MCDE_PBCBCRC10 0x00000C38 +#define MCDE_PBCBCRC10_CTLI_SHIFT 0 +#define MCDE_PBCBCRC10_CTLI_MASK 0xFFFFFFFF +#define MCDE_PBCBCRC10_CTLI(__x) \ + MCDE_VAL2REG(MCDE_PBCBCRC10, CTLI, __x) +#define MCDE_PBCBCRC01 0x00000C48 +#define MCDE_PBCBCRC01_GROUPOFFSET 0x4 +#define MCDE_PBCBCRC01_CTLI_SHIFT 0 +#define MCDE_PBCBCRC01_CTLI_MASK 0xFFFFFFFF +#define MCDE_PBCBCRC01_CTLI(__x) \ + MCDE_VAL2REG(MCDE_PBCBCRC01, CTLI, __x) +#define MCDE_PBCBCRC11 0x00000C4C +#define MCDE_PBCBCRC11_CTLI_SHIFT 0 +#define MCDE_PBCBCRC11_CTLI_MASK 0xFFFFFFFF +#define MCDE_PBCBCRC11_CTLI(__x) \ + MCDE_VAL2REG(MCDE_PBCBCRC11, CTLI, __x) +#define MCDE_VSCRC0 0x00000C5C +#define MCDE_VSCRC0_GROUPOFFSET 0x4 +#define MCDE_VSCRC0_VSPMIN_SHIFT 0 +#define MCDE_VSCRC0_VSPMIN_MASK 0x00000FFF +#define MCDE_VSCRC0_VSPMIN(__x) \ + MCDE_VAL2REG(MCDE_VSCRC0, VSPMIN, __x) +#define MCDE_VSCRC0_VSPMAX_SHIFT 12 +#define MCDE_VSCRC0_VSPMAX_MASK 0x00FFF000 +#define MCDE_VSCRC0_VSPMAX(__x) \ + MCDE_VAL2REG(MCDE_VSCRC0, VSPMAX, __x) +#define MCDE_VSCRC0_VSPDIV_SHIFT 24 +#define MCDE_VSCRC0_VSPDIV_MASK 0x07000000 +#define MCDE_VSCRC0_VSPDIV_MCDECLK_DIV_1 0 +#define MCDE_VSCRC0_VSPDIV_MCDECLK_DIV_2 1 +#define MCDE_VSCRC0_VSPDIV_MCDECLK_DIV_4 2 +#define MCDE_VSCRC0_VSPDIV_MCDECLK_DIV_8 3 +#define MCDE_VSCRC0_VSPDIV_MCDECLK_DIV_16 4 +#define MCDE_VSCRC0_VSPDIV_MCDECLK_DIV_32 5 +#define MCDE_VSCRC0_VSPDIV_MCDECLK_DIV_64 6 +#define MCDE_VSCRC0_VSPDIV_MCDECLK_DIV_128 7 +#define MCDE_VSCRC0_VSPDIV_ENUM(__x) \ + MCDE_VAL2REG(MCDE_VSCRC0, VSPDIV, MCDE_VSCRC0_VSPDIV_##__x) +#define MCDE_VSCRC0_VSPDIV(__x) \ + MCDE_VAL2REG(MCDE_VSCRC0, VSPDIV, __x) +#define MCDE_VSCRC0_VSPOL_SHIFT 27 +#define MCDE_VSCRC0_VSPOL_MASK 0x08000000 +#define MCDE_VSCRC0_VSPOL_ACTIVE_HIGH 0 +#define MCDE_VSCRC0_VSPOL_ACTIVE_LOW 1 +#define MCDE_VSCRC0_VSPOL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_VSCRC0, VSPOL, MCDE_VSCRC0_VSPOL_##__x) +#define MCDE_VSCRC0_VSPOL(__x) \ + MCDE_VAL2REG(MCDE_VSCRC0, VSPOL, __x) +#define MCDE_VSCRC0_VSSEL_SHIFT 28 +#define MCDE_VSCRC0_VSSEL_MASK 0x10000000 +#define MCDE_VSCRC0_VSSEL_VSYNC0 0 +#define MCDE_VSCRC0_VSSEL_VSYNC1 1 +#define MCDE_VSCRC0_VSSEL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_VSCRC0, VSSEL, MCDE_VSCRC0_VSSEL_##__x) +#define MCDE_VSCRC0_VSSEL(__x) \ + MCDE_VAL2REG(MCDE_VSCRC0, VSSEL, __x) +#define MCDE_VSCRC0_VSDBL_SHIFT 29 +#define MCDE_VSCRC0_VSDBL_MASK 0xE0000000 +#define MCDE_VSCRC0_VSDBL(__x) \ + MCDE_VAL2REG(MCDE_VSCRC0, VSDBL, __x) +#define MCDE_VSCRC1 0x00000C60 +#define MCDE_VSCRC1_VSPMIN_SHIFT 0 +#define MCDE_VSCRC1_VSPMIN_MASK 0x00000FFF +#define MCDE_VSCRC1_VSPMIN(__x) \ + MCDE_VAL2REG(MCDE_VSCRC1, VSPMIN, __x) +#define MCDE_VSCRC1_VSPMAX_SHIFT 12 +#define MCDE_VSCRC1_VSPMAX_MASK 0x00FFF000 +#define MCDE_VSCRC1_VSPMAX(__x) \ + MCDE_VAL2REG(MCDE_VSCRC1, VSPMAX, __x) +#define MCDE_VSCRC1_VSPDIV_SHIFT 24 +#define MCDE_VSCRC1_VSPDIV_MASK 0x07000000 +#define MCDE_VSCRC1_VSPDIV_MCDECLK_DIV_1 0 +#define MCDE_VSCRC1_VSPDIV_MCDECLK_DIV_2 1 +#define MCDE_VSCRC1_VSPDIV_MCDECLK_DIV_4 2 +#define MCDE_VSCRC1_VSPDIV_MCDECLK_DIV_8 3 +#define MCDE_VSCRC1_VSPDIV_MCDECLK_DIV_16 4 +#define MCDE_VSCRC1_VSPDIV_MCDECLK_DIV_32 5 +#define MCDE_VSCRC1_VSPDIV_MCDECLK_DIV_64 6 +#define MCDE_VSCRC1_VSPDIV_MCDECLK_DIV_128 7 +#define MCDE_VSCRC1_VSPDIV_ENUM(__x) \ + MCDE_VAL2REG(MCDE_VSCRC1, VSPDIV, MCDE_VSCRC1_VSPDIV_##__x) +#define MCDE_VSCRC1_VSPDIV(__x) \ + MCDE_VAL2REG(MCDE_VSCRC1, VSPDIV, __x) +#define MCDE_VSCRC1_VSPOL_SHIFT 27 +#define MCDE_VSCRC1_VSPOL_MASK 0x08000000 +#define MCDE_VSCRC1_VSPOL_ACTIVE_HIGH 0 +#define MCDE_VSCRC1_VSPOL_ACTIVE_LOW 1 +#define MCDE_VSCRC1_VSPOL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_VSCRC1, VSPOL, MCDE_VSCRC1_VSPOL_##__x) +#define MCDE_VSCRC1_VSPOL(__x) \ + MCDE_VAL2REG(MCDE_VSCRC1, VSPOL, __x) +#define MCDE_VSCRC1_VSSEL_SHIFT 28 +#define MCDE_VSCRC1_VSSEL_MASK 0x10000000 +#define MCDE_VSCRC1_VSSEL_VSYNC0 0 +#define MCDE_VSCRC1_VSSEL_VSYNC1 1 +#define MCDE_VSCRC1_VSSEL_ENUM(__x) \ + MCDE_VAL2REG(MCDE_VSCRC1, VSSEL, MCDE_VSCRC1_VSSEL_##__x) +#define MCDE_VSCRC1_VSSEL(__x) \ + MCDE_VAL2REG(MCDE_VSCRC1, VSSEL, __x) +#define MCDE_VSCRC1_VSDBL_SHIFT 29 +#define MCDE_VSCRC1_VSDBL_MASK 0xE0000000 +#define MCDE_VSCRC1_VSDBL(__x) \ + MCDE_VAL2REG(MCDE_VSCRC1, VSDBL, __x) +#define MCDE_SCTRC 0x00000C64 +#define MCDE_SCTRC_SYNCDELC0_SHIFT 0 +#define MCDE_SCTRC_SYNCDELC0_MASK 0x000000FF +#define MCDE_SCTRC_SYNCDELC0(__x) \ + MCDE_VAL2REG(MCDE_SCTRC, SYNCDELC0, __x) +#define MCDE_SCTRC_SYNCDELC1_SHIFT 8 +#define MCDE_SCTRC_SYNCDELC1_MASK 0x0000FF00 +#define MCDE_SCTRC_SYNCDELC1(__x) \ + MCDE_VAL2REG(MCDE_SCTRC, SYNCDELC1, __x) +#define MCDE_SCTRC_TRDELC_SHIFT 16 +#define MCDE_SCTRC_TRDELC_MASK 0x0FFF0000 +#define MCDE_SCTRC_TRDELC(__x) \ + MCDE_VAL2REG(MCDE_SCTRC, TRDELC, __x) +#define MCDE_SCSRC 0x00000C68 +#define MCDE_SCSRC_VSTAC0_SHIFT 0 +#define MCDE_SCSRC_VSTAC0_MASK 0x00000001 +#define MCDE_SCSRC_VSTAC0(__x) \ + MCDE_VAL2REG(MCDE_SCSRC, VSTAC0, __x) +#define MCDE_SCSRC_VSTAC1_SHIFT 1 +#define MCDE_SCSRC_VSTAC1_MASK 0x00000002 +#define MCDE_SCSRC_VSTAC1(__x) \ + MCDE_VAL2REG(MCDE_SCSRC, VSTAC1, __x) +#define MCDE_BCNR0 0x00000C6C +#define MCDE_BCNR0_GROUPOFFSET 0x4 +#define MCDE_BCNR0_BCN_SHIFT 0 +#define MCDE_BCNR0_BCN_MASK 0x000000FF +#define MCDE_BCNR0_BCN(__x) \ + MCDE_VAL2REG(MCDE_BCNR0, BCN, __x) +#define MCDE_BCNR1 0x00000C70 +#define MCDE_BCNR1_BCN_SHIFT 0 +#define MCDE_BCNR1_BCN_MASK 0x000000FF +#define MCDE_BCNR1_BCN(__x) \ + MCDE_VAL2REG(MCDE_BCNR1, BCN, __x) +#define MCDE_CSCDTR0 0x00000C74 +#define MCDE_CSCDTR0_GROUPOFFSET 0x4 +#define MCDE_CSCDTR0_CSACT_SHIFT 0 +#define MCDE_CSCDTR0_CSACT_MASK 0x000000FF +#define MCDE_CSCDTR0_CSACT(__x) \ + MCDE_VAL2REG(MCDE_CSCDTR0, CSACT, __x) +#define MCDE_CSCDTR0_CSDEACT_SHIFT 8 +#define MCDE_CSCDTR0_CSDEACT_MASK 0x0000FF00 +#define MCDE_CSCDTR0_CSDEACT(__x) \ + MCDE_VAL2REG(MCDE_CSCDTR0, CSDEACT, __x) +#define MCDE_CSCDTR0_CDACT_SHIFT 16 +#define MCDE_CSCDTR0_CDACT_MASK 0x00FF0000 +#define MCDE_CSCDTR0_CDACT(__x) \ + MCDE_VAL2REG(MCDE_CSCDTR0, CDACT, __x) +#define MCDE_CSCDTR0_CDDEACT_SHIFT 24 +#define MCDE_CSCDTR0_CDDEACT_MASK 0xFF000000 +#define MCDE_CSCDTR0_CDDEACT(__x) \ + MCDE_VAL2REG(MCDE_CSCDTR0, CDDEACT, __x) +#define MCDE_CSCDTR1 0x00000C78 +#define MCDE_CSCDTR1_CSACT_SHIFT 0 +#define MCDE_CSCDTR1_CSACT_MASK 0x000000FF +#define MCDE_CSCDTR1_CSACT(__x) \ + MCDE_VAL2REG(MCDE_CSCDTR1, CSACT, __x) +#define MCDE_CSCDTR1_CSDEACT_SHIFT 8 +#define MCDE_CSCDTR1_CSDEACT_MASK 0x0000FF00 +#define MCDE_CSCDTR1_CSDEACT(__x) \ + MCDE_VAL2REG(MCDE_CSCDTR1, CSDEACT, __x) +#define MCDE_CSCDTR1_CDACT_SHIFT 16 +#define MCDE_CSCDTR1_CDACT_MASK 0x00FF0000 +#define MCDE_CSCDTR1_CDACT(__x) \ + MCDE_VAL2REG(MCDE_CSCDTR1, CDACT, __x) +#define MCDE_CSCDTR1_CDDEACT_SHIFT 24 +#define MCDE_CSCDTR1_CDDEACT_MASK 0xFF000000 +#define MCDE_CSCDTR1_CDDEACT(__x) \ + MCDE_VAL2REG(MCDE_CSCDTR1, CDDEACT, __x) +#define MCDE_RDWRTR0 0x00000C7C +#define MCDE_RDWRTR0_GROUPOFFSET 0x4 +#define MCDE_RDWRTR0_RWACT_SHIFT 0 +#define MCDE_RDWRTR0_RWACT_MASK 0x000000FF +#define MCDE_RDWRTR0_RWACT(__x) \ + MCDE_VAL2REG(MCDE_RDWRTR0, RWACT, __x) +#define MCDE_RDWRTR0_RWDEACT_SHIFT 8 +#define MCDE_RDWRTR0_RWDEACT_MASK 0x0000FF00 +#define MCDE_RDWRTR0_RWDEACT(__x) \ + MCDE_VAL2REG(MCDE_RDWRTR0, RWDEACT, __x) +#define MCDE_RDWRTR0_MOTINT_SHIFT 16 +#define MCDE_RDWRTR0_MOTINT_MASK 0x00010000 +#define MCDE_RDWRTR0_MOTINT(__x) \ + MCDE_VAL2REG(MCDE_RDWRTR0, MOTINT, __x) +#define MCDE_RDWRTR1 0x00000C80 +#define MCDE_RDWRTR1_RWACT_SHIFT 0 +#define MCDE_RDWRTR1_RWACT_MASK 0x000000FF +#define MCDE_RDWRTR1_RWACT(__x) \ + MCDE_VAL2REG(MCDE_RDWRTR1, RWACT, __x) +#define MCDE_RDWRTR1_RWDEACT_SHIFT 8 +#define MCDE_RDWRTR1_RWDEACT_MASK 0x0000FF00 +#define MCDE_RDWRTR1_RWDEACT(__x) \ + MCDE_VAL2REG(MCDE_RDWRTR1, RWDEACT, __x) +#define MCDE_RDWRTR1_MOTINT_SHIFT 16 +#define MCDE_RDWRTR1_MOTINT_MASK 0x00010000 +#define MCDE_RDWRTR1_MOTINT(__x) \ + MCDE_VAL2REG(MCDE_RDWRTR1, MOTINT, __x) +#define MCDE_DOTR0 0x00000C84 +#define MCDE_DOTR0_GROUPOFFSET 0x4 +#define MCDE_DOTR0_DOACT_SHIFT 0 +#define MCDE_DOTR0_DOACT_MASK 0x000000FF +#define MCDE_DOTR0_DOACT(__x) \ + MCDE_VAL2REG(MCDE_DOTR0, DOACT, __x) +#define MCDE_DOTR0_DODEACT_SHIFT 8 +#define MCDE_DOTR0_DODEACT_MASK 0x0000FF00 +#define MCDE_DOTR0_DODEACT(__x) \ + MCDE_VAL2REG(MCDE_DOTR0, DODEACT, __x) +#define MCDE_DOTR1 0x00000C88 +#define MCDE_DOTR1_DOACT_SHIFT 0 +#define MCDE_DOTR1_DOACT_MASK 0x000000FF +#define MCDE_DOTR1_DOACT(__x) \ + MCDE_VAL2REG(MCDE_DOTR1, DOACT, __x) +#define MCDE_DOTR1_DODEACT_SHIFT 8 +#define MCDE_DOTR1_DODEACT_MASK 0x0000FF00 +#define MCDE_DOTR1_DODEACT(__x) \ + MCDE_VAL2REG(MCDE_DOTR1, DODEACT, __x) +#define MCDE_WDATADC0 0x00000C94 +#define MCDE_WDATADC0_GROUPOFFSET 0x4 +#define MCDE_WDATADC0_DATAVALUE_SHIFT 0 +#define MCDE_WDATADC0_DATAVALUE_MASK 0x00FFFFFF +#define MCDE_WDATADC0_DATAVALUE(__x) \ + MCDE_VAL2REG(MCDE_WDATADC0, DATAVALUE, __x) +#define MCDE_WDATADC0_DC_SHIFT 24 +#define MCDE_WDATADC0_DC_MASK 0x01000000 +#define MCDE_WDATADC0_DC(__x) \ + MCDE_VAL2REG(MCDE_WDATADC0, DC, __x) +#define MCDE_WDATADC1 0x00000C98 +#define MCDE_WDATADC1_DATAVALUE_SHIFT 0 +#define MCDE_WDATADC1_DATAVALUE_MASK 0x00FFFFFF +#define MCDE_WDATADC1_DATAVALUE(__x) \ + MCDE_VAL2REG(MCDE_WDATADC1, DATAVALUE, __x) +#define MCDE_WDATADC1_DC_SHIFT 24 +#define MCDE_WDATADC1_DC_MASK 0x01000000 +#define MCDE_WDATADC1_DC(__x) \ + MCDE_VAL2REG(MCDE_WDATADC1, DC, __x) +#define MCDE_RDATADC0 0x00000C9C +#define MCDE_RDATADC0_GROUPOFFSET 0x4 +#define MCDE_RDATADC0_DATAREADFROMDISPLAYMODULE_SHIFT 0 +#define MCDE_RDATADC0_DATAREADFROMDISPLAYMODULE_MASK 0x0000FFFF +#define MCDE_RDATADC0_DATAREADFROMDISPLAYMODULE(__x) \ + MCDE_VAL2REG(MCDE_RDATADC0, DATAREADFROMDISPLAYMODULE, __x) +#define MCDE_RDATADC0_STARTREAD_SHIFT 16 +#define MCDE_RDATADC0_STARTREAD_MASK 0x00010000 +#define MCDE_RDATADC0_STARTREAD(__x) \ + MCDE_VAL2REG(MCDE_RDATADC0, STARTREAD, __x) +#define MCDE_RDATADC1 0x00000CA0 +#define MCDE_RDATADC1_DATAREADFROMDISPLAYMODULE_SHIFT 0 +#define MCDE_RDATADC1_DATAREADFROMDISPLAYMODULE_MASK 0x0000FFFF +#define MCDE_RDATADC1_DATAREADFROMDISPLAYMODULE(__x) \ + MCDE_VAL2REG(MCDE_RDATADC1, DATAREADFROMDISPLAYMODULE, __x) +#define MCDE_RDATADC1_STARTREAD_SHIFT 16 +#define MCDE_RDATADC1_STARTREAD_MASK 0x00010000 +#define MCDE_RDATADC1_STARTREAD(__x) \ + MCDE_VAL2REG(MCDE_RDATADC1, STARTREAD, __x) +#define MCDE_STATC 0x00000CA4 +#define MCDE_STATC_STATBUSY0_SHIFT 0 +#define MCDE_STATC_STATBUSY0_MASK 0x00000001 +#define MCDE_STATC_STATBUSY0(__x) \ + MCDE_VAL2REG(MCDE_STATC, STATBUSY0, __x) +#define MCDE_STATC_STATBUSY1_SHIFT 5 +#define MCDE_STATC_STATBUSY1_MASK 0x00000020 +#define MCDE_STATC_STATBUSY1(__x) \ + MCDE_VAL2REG(MCDE_STATC, STATBUSY1, __x) +#define MCDE_CTRLC0 0x00000CA8 +#define MCDE_CTRLC0_GROUPOFFSET 0x4 +#define MCDE_CTRLC0_FIFOWTRMRK_SHIFT 0 +#define MCDE_CTRLC0_FIFOWTRMRK_MASK 0x000000FF +#define MCDE_CTRLC0_FIFOWTRMRK(__x) \ + MCDE_VAL2REG(MCDE_CTRLC0, FIFOWTRMRK, __x) +#define MCDE_CTRLC0_FIFOEMPTY_SHIFT 12 +#define MCDE_CTRLC0_FIFOEMPTY_MASK 0x00001000 +#define MCDE_CTRLC0_FIFOEMPTY(__x) \ + MCDE_VAL2REG(MCDE_CTRLC0, FIFOEMPTY, __x) +#define MCDE_CTRLC0_FIFOFULL_SHIFT 13 +#define MCDE_CTRLC0_FIFOFULL_MASK 0x00002000 +#define MCDE_CTRLC0_FIFOFULL(__x) \ + MCDE_VAL2REG(MCDE_CTRLC0, FIFOFULL, __x) +#define MCDE_CTRLC0_FORMID_SHIFT 16 +#define MCDE_CTRLC0_FORMID_MASK 0x00070000 +#define MCDE_CTRLC0_FORMID_DSI0VID 0 +#define MCDE_CTRLC0_FORMID_DSI0CMD 1 +#define MCDE_CTRLC0_FORMID_DSI1VID 2 +#define MCDE_CTRLC0_FORMID_DSI1CMD 3 +#define MCDE_CTRLC0_FORMID_DSI2VID 4 +#define MCDE_CTRLC0_FORMID_DSI2CMD 5 +#define MCDE_CTRLC0_FORMID_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CTRLC0, FORMID, MCDE_CTRLC0_FORMID_##__x) +#define MCDE_CTRLC0_FORMID(__x) \ + MCDE_VAL2REG(MCDE_CTRLC0, FORMID, __x) +#define MCDE_CTRLC0_FORMTYPE_SHIFT 20 +#define MCDE_CTRLC0_FORMTYPE_MASK 0x00700000 +#define MCDE_CTRLC0_FORMTYPE_DPITV 0 +#define MCDE_CTRLC0_FORMTYPE_DBI 1 +#define MCDE_CTRLC0_FORMTYPE_DSI 2 +#define MCDE_CTRLC0_FORMTYPE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CTRLC0, FORMTYPE, MCDE_CTRLC0_FORMTYPE_##__x) +#define MCDE_CTRLC0_FORMTYPE(__x) \ + MCDE_VAL2REG(MCDE_CTRLC0, FORMTYPE, __x) +#define MCDE_CTRLC1 0x00000CAC +#define MCDE_CTRLC1_FIFOWTRMRK_SHIFT 0 +#define MCDE_CTRLC1_FIFOWTRMRK_MASK 0x000000FF +#define MCDE_CTRLC1_FIFOWTRMRK(__x) \ + MCDE_VAL2REG(MCDE_CTRLC1, FIFOWTRMRK, __x) +#define MCDE_CTRLC1_FIFOEMPTY_SHIFT 12 +#define MCDE_CTRLC1_FIFOEMPTY_MASK 0x00001000 +#define MCDE_CTRLC1_FIFOEMPTY(__x) \ + MCDE_VAL2REG(MCDE_CTRLC1, FIFOEMPTY, __x) +#define MCDE_CTRLC1_FIFOFULL_SHIFT 13 +#define MCDE_CTRLC1_FIFOFULL_MASK 0x00002000 +#define MCDE_CTRLC1_FIFOFULL(__x) \ + MCDE_VAL2REG(MCDE_CTRLC1, FIFOFULL, __x) +#define MCDE_CTRLC1_FORMID_SHIFT 16 +#define MCDE_CTRLC1_FORMID_MASK 0x00070000 +#define MCDE_CTRLC1_FORMID_DSI0VID 0 +#define MCDE_CTRLC1_FORMID_DSI0CMD 1 +#define MCDE_CTRLC1_FORMID_DSI1VID 2 +#define MCDE_CTRLC1_FORMID_DSI1CMD 3 +#define MCDE_CTRLC1_FORMID_DSI2VID 4 +#define MCDE_CTRLC1_FORMID_DSI2CMD 5 +#define MCDE_CTRLC1_FORMID_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CTRLC1, FORMID, MCDE_CTRLC1_FORMID_##__x) +#define MCDE_CTRLC1_FORMID(__x) \ + MCDE_VAL2REG(MCDE_CTRLC1, FORMID, __x) +#define MCDE_CTRLC1_FORMTYPE_SHIFT 20 +#define MCDE_CTRLC1_FORMTYPE_MASK 0x00700000 +#define MCDE_CTRLC1_FORMTYPE_DPITV 0 +#define MCDE_CTRLC1_FORMTYPE_DBI 1 +#define MCDE_CTRLC1_FORMTYPE_DSI 2 +#define MCDE_CTRLC1_FORMTYPE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_CTRLC1, FORMTYPE, MCDE_CTRLC1_FORMTYPE_##__x) +#define MCDE_CTRLC1_FORMTYPE(__x) \ + MCDE_VAL2REG(MCDE_CTRLC1, FORMTYPE, __x) +#define MCDE_DSIVID0CONF0 0x00000E00 +#define MCDE_DSIVID0CONF0_GROUPOFFSET 0x20 +#define MCDE_DSIVID0CONF0_BLANKING_SHIFT 0 +#define MCDE_DSIVID0CONF0_BLANKING_MASK 0x000000FF +#define MCDE_DSIVID0CONF0_BLANKING(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0CONF0, BLANKING, __x) +#define MCDE_DSIVID0CONF0_VID_MODE_SHIFT 12 +#define MCDE_DSIVID0CONF0_VID_MODE_MASK 0x00001000 +#define MCDE_DSIVID0CONF0_VID_MODE_CMD 0 +#define MCDE_DSIVID0CONF0_VID_MODE_VID 1 +#define MCDE_DSIVID0CONF0_VID_MODE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0CONF0, VID_MODE, \ + MCDE_DSIVID0CONF0_VID_MODE_##__x) +#define MCDE_DSIVID0CONF0_VID_MODE(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0CONF0, VID_MODE, __x) +#define MCDE_DSIVID0CONF0_CMD8_SHIFT 13 +#define MCDE_DSIVID0CONF0_CMD8_MASK 0x00002000 +#define MCDE_DSIVID0CONF0_CMD8(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0CONF0, CMD8, __x) +#define MCDE_DSIVID0CONF0_BIT_SWAP_SHIFT 16 +#define MCDE_DSIVID0CONF0_BIT_SWAP_MASK 0x00010000 +#define MCDE_DSIVID0CONF0_BIT_SWAP(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0CONF0, BIT_SWAP, __x) +#define MCDE_DSIVID0CONF0_BYTE_SWAP_SHIFT 17 +#define MCDE_DSIVID0CONF0_BYTE_SWAP_MASK 0x00020000 +#define MCDE_DSIVID0CONF0_BYTE_SWAP(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0CONF0, BYTE_SWAP, __x) +#define MCDE_DSIVID0CONF0_DCSVID_NOTGEN_SHIFT 18 +#define MCDE_DSIVID0CONF0_DCSVID_NOTGEN_MASK 0x00040000 +#define MCDE_DSIVID0CONF0_DCSVID_NOTGEN(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0CONF0, DCSVID_NOTGEN, __x) +#define MCDE_DSIVID0CONF0_PACKING_SHIFT 20 +#define MCDE_DSIVID0CONF0_PACKING_MASK 0x00700000 +#define MCDE_DSIVID0CONF0_PACKING_RGB565 0 +#define MCDE_DSIVID0CONF0_PACKING_RGB666 1 +#define MCDE_DSIVID0CONF0_PACKING_RGB888 2 +#define MCDE_DSIVID0CONF0_PACKING_BGR888 3 +#define MCDE_DSIVID0CONF0_PACKING_HDTV 4 +#define MCDE_DSIVID0CONF0_PACKING_ENUM(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0CONF0, PACKING, \ + MCDE_DSIVID0CONF0_PACKING_##__x) +#define MCDE_DSIVID0CONF0_PACKING(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0CONF0, PACKING, __x) +#define MCDE_DSICMD0CONF0 0x00000E20 +#define MCDE_DSICMD0CONF0_BLANKING_SHIFT 0 +#define MCDE_DSICMD0CONF0_BLANKING_MASK 0x000000FF +#define MCDE_DSICMD0CONF0_BLANKING(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0CONF0, BLANKING, __x) +#define MCDE_DSICMD0CONF0_VID_MODE_SHIFT 12 +#define MCDE_DSICMD0CONF0_VID_MODE_MASK 0x00001000 +#define MCDE_DSICMD0CONF0_VID_MODE_CMD 0 +#define MCDE_DSICMD0CONF0_VID_MODE_VID 1 +#define MCDE_DSICMD0CONF0_VID_MODE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0CONF0, VID_MODE, \ + MCDE_DSICMD0CONF0_VID_MODE_##__x) +#define MCDE_DSICMD0CONF0_VID_MODE(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0CONF0, VID_MODE, __x) +#define MCDE_DSICMD0CONF0_CMD8_SHIFT 13 +#define MCDE_DSICMD0CONF0_CMD8_MASK 0x00002000 +#define MCDE_DSICMD0CONF0_CMD8(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0CONF0, CMD8, __x) +#define MCDE_DSICMD0CONF0_BIT_SWAP_SHIFT 16 +#define MCDE_DSICMD0CONF0_BIT_SWAP_MASK 0x00010000 +#define MCDE_DSICMD0CONF0_BIT_SWAP(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0CONF0, BIT_SWAP, __x) +#define MCDE_DSICMD0CONF0_BYTE_SWAP_SHIFT 17 +#define MCDE_DSICMD0CONF0_BYTE_SWAP_MASK 0x00020000 +#define MCDE_DSICMD0CONF0_BYTE_SWAP(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0CONF0, BYTE_SWAP, __x) +#define MCDE_DSICMD0CONF0_DCSVID_NOTGEN_SHIFT 18 +#define MCDE_DSICMD0CONF0_DCSVID_NOTGEN_MASK 0x00040000 +#define MCDE_DSICMD0CONF0_DCSVID_NOTGEN(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0CONF0, DCSVID_NOTGEN, __x) +#define MCDE_DSICMD0CONF0_PACKING_SHIFT 20 +#define MCDE_DSICMD0CONF0_PACKING_MASK 0x00700000 +#define MCDE_DSICMD0CONF0_PACKING_RGB565 0 +#define MCDE_DSICMD0CONF0_PACKING_RGB666 1 +#define MCDE_DSICMD0CONF0_PACKING_RGB888 2 +#define MCDE_DSICMD0CONF0_PACKING_BGR888 3 +#define MCDE_DSICMD0CONF0_PACKING_HDTV 4 +#define MCDE_DSICMD0CONF0_PACKING_ENUM(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0CONF0, PACKING, \ + MCDE_DSICMD0CONF0_PACKING_##__x) +#define MCDE_DSICMD0CONF0_PACKING(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0CONF0, PACKING, __x) +#define MCDE_DSIVID1CONF0 0x00000E40 +#define MCDE_DSIVID1CONF0_BLANKING_SHIFT 0 +#define MCDE_DSIVID1CONF0_BLANKING_MASK 0x000000FF +#define MCDE_DSIVID1CONF0_BLANKING(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1CONF0, BLANKING, __x) +#define MCDE_DSIVID1CONF0_VID_MODE_SHIFT 12 +#define MCDE_DSIVID1CONF0_VID_MODE_MASK 0x00001000 +#define MCDE_DSIVID1CONF0_VID_MODE_CMD 0 +#define MCDE_DSIVID1CONF0_VID_MODE_VID 1 +#define MCDE_DSIVID1CONF0_VID_MODE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1CONF0, VID_MODE, \ + MCDE_DSIVID1CONF0_VID_MODE_##__x) +#define MCDE_DSIVID1CONF0_VID_MODE(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1CONF0, VID_MODE, __x) +#define MCDE_DSIVID1CONF0_CMD8_SHIFT 13 +#define MCDE_DSIVID1CONF0_CMD8_MASK 0x00002000 +#define MCDE_DSIVID1CONF0_CMD8(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1CONF0, CMD8, __x) +#define MCDE_DSIVID1CONF0_BIT_SWAP_SHIFT 16 +#define MCDE_DSIVID1CONF0_BIT_SWAP_MASK 0x00010000 +#define MCDE_DSIVID1CONF0_BIT_SWAP(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1CONF0, BIT_SWAP, __x) +#define MCDE_DSIVID1CONF0_BYTE_SWAP_SHIFT 17 +#define MCDE_DSIVID1CONF0_BYTE_SWAP_MASK 0x00020000 +#define MCDE_DSIVID1CONF0_BYTE_SWAP(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1CONF0, BYTE_SWAP, __x) +#define MCDE_DSIVID1CONF0_DCSVID_NOTGEN_SHIFT 18 +#define MCDE_DSIVID1CONF0_DCSVID_NOTGEN_MASK 0x00040000 +#define MCDE_DSIVID1CONF0_DCSVID_NOTGEN(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1CONF0, DCSVID_NOTGEN, __x) +#define MCDE_DSIVID1CONF0_PACKING_SHIFT 20 +#define MCDE_DSIVID1CONF0_PACKING_MASK 0x00700000 +#define MCDE_DSIVID1CONF0_PACKING_RGB565 0 +#define MCDE_DSIVID1CONF0_PACKING_RGB666 1 +#define MCDE_DSIVID1CONF0_PACKING_RGB888 2 +#define MCDE_DSIVID1CONF0_PACKING_BGR888 3 +#define MCDE_DSIVID1CONF0_PACKING_HDTV 4 +#define MCDE_DSIVID1CONF0_PACKING_ENUM(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1CONF0, PACKING, \ + MCDE_DSIVID1CONF0_PACKING_##__x) +#define MCDE_DSIVID1CONF0_PACKING(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1CONF0, PACKING, __x) +#define MCDE_DSICMD1CONF0 0x00000E60 +#define MCDE_DSICMD1CONF0_BLANKING_SHIFT 0 +#define MCDE_DSICMD1CONF0_BLANKING_MASK 0x000000FF +#define MCDE_DSICMD1CONF0_BLANKING(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1CONF0, BLANKING, __x) +#define MCDE_DSICMD1CONF0_VID_MODE_SHIFT 12 +#define MCDE_DSICMD1CONF0_VID_MODE_MASK 0x00001000 +#define MCDE_DSICMD1CONF0_VID_MODE_CMD 0 +#define MCDE_DSICMD1CONF0_VID_MODE_VID 1 +#define MCDE_DSICMD1CONF0_VID_MODE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1CONF0, VID_MODE, \ + MCDE_DSICMD1CONF0_VID_MODE_##__x) +#define MCDE_DSICMD1CONF0_VID_MODE(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1CONF0, VID_MODE, __x) +#define MCDE_DSICMD1CONF0_CMD8_SHIFT 13 +#define MCDE_DSICMD1CONF0_CMD8_MASK 0x00002000 +#define MCDE_DSICMD1CONF0_CMD8(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1CONF0, CMD8, __x) +#define MCDE_DSICMD1CONF0_BIT_SWAP_SHIFT 16 +#define MCDE_DSICMD1CONF0_BIT_SWAP_MASK 0x00010000 +#define MCDE_DSICMD1CONF0_BIT_SWAP(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1CONF0, BIT_SWAP, __x) +#define MCDE_DSICMD1CONF0_BYTE_SWAP_SHIFT 17 +#define MCDE_DSICMD1CONF0_BYTE_SWAP_MASK 0x00020000 +#define MCDE_DSICMD1CONF0_BYTE_SWAP(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1CONF0, BYTE_SWAP, __x) +#define MCDE_DSICMD1CONF0_DCSVID_NOTGEN_SHIFT 18 +#define MCDE_DSICMD1CONF0_DCSVID_NOTGEN_MASK 0x00040000 +#define MCDE_DSICMD1CONF0_DCSVID_NOTGEN(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1CONF0, DCSVID_NOTGEN, __x) +#define MCDE_DSICMD1CONF0_PACKING_SHIFT 20 +#define MCDE_DSICMD1CONF0_PACKING_MASK 0x00700000 +#define MCDE_DSICMD1CONF0_PACKING_RGB565 0 +#define MCDE_DSICMD1CONF0_PACKING_RGB666 1 +#define MCDE_DSICMD1CONF0_PACKING_RGB888 2 +#define MCDE_DSICMD1CONF0_PACKING_BGR888 3 +#define MCDE_DSICMD1CONF0_PACKING_HDTV 4 +#define MCDE_DSICMD1CONF0_PACKING_ENUM(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1CONF0, PACKING, \ + MCDE_DSICMD1CONF0_PACKING_##__x) +#define MCDE_DSICMD1CONF0_PACKING(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1CONF0, PACKING, __x) +#define MCDE_DSIVID2CONF0 0x00000E80 +#define MCDE_DSIVID2CONF0_BLANKING_SHIFT 0 +#define MCDE_DSIVID2CONF0_BLANKING_MASK 0x000000FF +#define MCDE_DSIVID2CONF0_BLANKING(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2CONF0, BLANKING, __x) +#define MCDE_DSIVID2CONF0_VID_MODE_SHIFT 12 +#define MCDE_DSIVID2CONF0_VID_MODE_MASK 0x00001000 +#define MCDE_DSIVID2CONF0_VID_MODE_CMD 0 +#define MCDE_DSIVID2CONF0_VID_MODE_VID 1 +#define MCDE_DSIVID2CONF0_VID_MODE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2CONF0, VID_MODE, \ + MCDE_DSIVID2CONF0_VID_MODE_##__x) +#define MCDE_DSIVID2CONF0_VID_MODE(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2CONF0, VID_MODE, __x) +#define MCDE_DSIVID2CONF0_CMD8_SHIFT 13 +#define MCDE_DSIVID2CONF0_CMD8_MASK 0x00002000 +#define MCDE_DSIVID2CONF0_CMD8(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2CONF0, CMD8, __x) +#define MCDE_DSIVID2CONF0_BIT_SWAP_SHIFT 16 +#define MCDE_DSIVID2CONF0_BIT_SWAP_MASK 0x00010000 +#define MCDE_DSIVID2CONF0_BIT_SWAP(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2CONF0, BIT_SWAP, __x) +#define MCDE_DSIVID2CONF0_BYTE_SWAP_SHIFT 17 +#define MCDE_DSIVID2CONF0_BYTE_SWAP_MASK 0x00020000 +#define MCDE_DSIVID2CONF0_BYTE_SWAP(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2CONF0, BYTE_SWAP, __x) +#define MCDE_DSIVID2CONF0_DCSVID_NOTGEN_SHIFT 18 +#define MCDE_DSIVID2CONF0_DCSVID_NOTGEN_MASK 0x00040000 +#define MCDE_DSIVID2CONF0_DCSVID_NOTGEN(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2CONF0, DCSVID_NOTGEN, __x) +#define MCDE_DSIVID2CONF0_PACKING_SHIFT 20 +#define MCDE_DSIVID2CONF0_PACKING_MASK 0x00700000 +#define MCDE_DSIVID2CONF0_PACKING_RGB565 0 +#define MCDE_DSIVID2CONF0_PACKING_RGB666 1 +#define MCDE_DSIVID2CONF0_PACKING_RGB888 2 +#define MCDE_DSIVID2CONF0_PACKING_BGR888 3 +#define MCDE_DSIVID2CONF0_PACKING_HDTV 4 +#define MCDE_DSIVID2CONF0_PACKING_ENUM(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2CONF0, PACKING, \ + MCDE_DSIVID2CONF0_PACKING_##__x) +#define MCDE_DSIVID2CONF0_PACKING(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2CONF0, PACKING, __x) +#define MCDE_DSICMD2CONF0 0x00000EA0 +#define MCDE_DSICMD2CONF0_BLANKING_SHIFT 0 +#define MCDE_DSICMD2CONF0_BLANKING_MASK 0x000000FF +#define MCDE_DSICMD2CONF0_BLANKING(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2CONF0, BLANKING, __x) +#define MCDE_DSICMD2CONF0_VID_MODE_SHIFT 12 +#define MCDE_DSICMD2CONF0_VID_MODE_MASK 0x00001000 +#define MCDE_DSICMD2CONF0_VID_MODE_CMD 0 +#define MCDE_DSICMD2CONF0_VID_MODE_VID 1 +#define MCDE_DSICMD2CONF0_VID_MODE_ENUM(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2CONF0, VID_MODE, \ + MCDE_DSICMD2CONF0_VID_MODE_##__x) +#define MCDE_DSICMD2CONF0_VID_MODE(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2CONF0, VID_MODE, __x) +#define MCDE_DSICMD2CONF0_CMD8_SHIFT 13 +#define MCDE_DSICMD2CONF0_CMD8_MASK 0x00002000 +#define MCDE_DSICMD2CONF0_CMD8(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2CONF0, CMD8, __x) +#define MCDE_DSICMD2CONF0_BIT_SWAP_SHIFT 16 +#define MCDE_DSICMD2CONF0_BIT_SWAP_MASK 0x00010000 +#define MCDE_DSICMD2CONF0_BIT_SWAP(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2CONF0, BIT_SWAP, __x) +#define MCDE_DSICMD2CONF0_BYTE_SWAP_SHIFT 17 +#define MCDE_DSICMD2CONF0_BYTE_SWAP_MASK 0x00020000 +#define MCDE_DSICMD2CONF0_BYTE_SWAP(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2CONF0, BYTE_SWAP, __x) +#define MCDE_DSICMD2CONF0_DCSVID_NOTGEN_SHIFT 18 +#define MCDE_DSICMD2CONF0_DCSVID_NOTGEN_MASK 0x00040000 +#define MCDE_DSICMD2CONF0_DCSVID_NOTGEN(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2CONF0, DCSVID_NOTGEN, __x) +#define MCDE_DSICMD2CONF0_PACKING_SHIFT 20 +#define MCDE_DSICMD2CONF0_PACKING_MASK 0x00700000 +#define MCDE_DSICMD2CONF0_PACKING_RGB565 0 +#define MCDE_DSICMD2CONF0_PACKING_RGB666 1 +#define MCDE_DSICMD2CONF0_PACKING_RGB888 2 +#define MCDE_DSICMD2CONF0_PACKING_BGR888 3 +#define MCDE_DSICMD2CONF0_PACKING_HDTV 4 +#define MCDE_DSICMD2CONF0_PACKING_ENUM(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2CONF0, PACKING, \ + MCDE_DSICMD2CONF0_PACKING_##__x) +#define MCDE_DSICMD2CONF0_PACKING(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2CONF0, PACKING, __x) +#define MCDE_DSIVID0FRAME 0x00000E04 +#define MCDE_DSIVID0FRAME_GROUPOFFSET 0x20 +#define MCDE_DSIVID0FRAME_FRAME_SHIFT 0 +#define MCDE_DSIVID0FRAME_FRAME_MASK 0x00FFFFFF +#define MCDE_DSIVID0FRAME_FRAME(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0FRAME, FRAME, __x) +#define MCDE_DSICMD0FRAME 0x00000E24 +#define MCDE_DSICMD0FRAME_FRAME_SHIFT 0 +#define MCDE_DSICMD0FRAME_FRAME_MASK 0x00FFFFFF +#define MCDE_DSICMD0FRAME_FRAME(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0FRAME, FRAME, __x) +#define MCDE_DSIVID1FRAME 0x00000E44 +#define MCDE_DSIVID1FRAME_FRAME_SHIFT 0 +#define MCDE_DSIVID1FRAME_FRAME_MASK 0x00FFFFFF +#define MCDE_DSIVID1FRAME_FRAME(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1FRAME, FRAME, __x) +#define MCDE_DSICMD1FRAME 0x00000E64 +#define MCDE_DSICMD1FRAME_FRAME_SHIFT 0 +#define MCDE_DSICMD1FRAME_FRAME_MASK 0x00FFFFFF +#define MCDE_DSICMD1FRAME_FRAME(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1FRAME, FRAME, __x) +#define MCDE_DSIVID2FRAME 0x00000E84 +#define MCDE_DSIVID2FRAME_FRAME_SHIFT 0 +#define MCDE_DSIVID2FRAME_FRAME_MASK 0x00FFFFFF +#define MCDE_DSIVID2FRAME_FRAME(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2FRAME, FRAME, __x) +#define MCDE_DSICMD2FRAME 0x00000EA4 +#define MCDE_DSICMD2FRAME_FRAME_SHIFT 0 +#define MCDE_DSICMD2FRAME_FRAME_MASK 0x00FFFFFF +#define MCDE_DSICMD2FRAME_FRAME(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2FRAME, FRAME, __x) +#define MCDE_DSIVID0PKT 0x00000E08 +#define MCDE_DSIVID0PKT_GROUPOFFSET 0x20 +#define MCDE_DSIVID0PKT_PACKET_SHIFT 0 +#define MCDE_DSIVID0PKT_PACKET_MASK 0x0000FFFF +#define MCDE_DSIVID0PKT_PACKET(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0PKT, PACKET, __x) +#define MCDE_DSICMD0PKT 0x00000E28 +#define MCDE_DSICMD0PKT_PACKET_SHIFT 0 +#define MCDE_DSICMD0PKT_PACKET_MASK 0x0000FFFF +#define MCDE_DSICMD0PKT_PACKET(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0PKT, PACKET, __x) +#define MCDE_DSIVID1PKT 0x00000E48 +#define MCDE_DSIVID1PKT_PACKET_SHIFT 0 +#define MCDE_DSIVID1PKT_PACKET_MASK 0x0000FFFF +#define MCDE_DSIVID1PKT_PACKET(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1PKT, PACKET, __x) +#define MCDE_DSICMD1PKT 0x00000E68 +#define MCDE_DSICMD1PKT_PACKET_SHIFT 0 +#define MCDE_DSICMD1PKT_PACKET_MASK 0x0000FFFF +#define MCDE_DSICMD1PKT_PACKET(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1PKT, PACKET, __x) +#define MCDE_DSIVID2PKT 0x00000E88 +#define MCDE_DSIVID2PKT_PACKET_SHIFT 0 +#define MCDE_DSIVID2PKT_PACKET_MASK 0x0000FFFF +#define MCDE_DSIVID2PKT_PACKET(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2PKT, PACKET, __x) +#define MCDE_DSICMD2PKT 0x00000EA8 +#define MCDE_DSICMD2PKT_PACKET_SHIFT 0 +#define MCDE_DSICMD2PKT_PACKET_MASK 0x0000FFFF +#define MCDE_DSICMD2PKT_PACKET(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2PKT, PACKET, __x) +#define MCDE_DSIVID0SYNC 0x00000E0C +#define MCDE_DSIVID0SYNC_GROUPOFFSET 0x20 +#define MCDE_DSIVID0SYNC_DMA_SHIFT 0 +#define MCDE_DSIVID0SYNC_DMA_MASK 0x00000FFF +#define MCDE_DSIVID0SYNC_DMA(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0SYNC, DMA, __x) +#define MCDE_DSIVID0SYNC_SW_SHIFT 16 +#define MCDE_DSIVID0SYNC_SW_MASK 0x0FFF0000 +#define MCDE_DSIVID0SYNC_SW(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0SYNC, SW, __x) +#define MCDE_DSICMD0SYNC 0x00000E2C +#define MCDE_DSICMD0SYNC_DMA_SHIFT 0 +#define MCDE_DSICMD0SYNC_DMA_MASK 0x00000FFF +#define MCDE_DSICMD0SYNC_DMA(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0SYNC, DMA, __x) +#define MCDE_DSICMD0SYNC_SW_SHIFT 16 +#define MCDE_DSICMD0SYNC_SW_MASK 0x0FFF0000 +#define MCDE_DSICMD0SYNC_SW(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0SYNC, SW, __x) +#define MCDE_DSIVID1SYNC 0x00000E4C +#define MCDE_DSIVID1SYNC_DMA_SHIFT 0 +#define MCDE_DSIVID1SYNC_DMA_MASK 0x00000FFF +#define MCDE_DSIVID1SYNC_DMA(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1SYNC, DMA, __x) +#define MCDE_DSIVID1SYNC_SW_SHIFT 16 +#define MCDE_DSIVID1SYNC_SW_MASK 0x0FFF0000 +#define MCDE_DSIVID1SYNC_SW(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1SYNC, SW, __x) +#define MCDE_DSICMD1SYNC 0x00000E6C +#define MCDE_DSICMD1SYNC_DMA_SHIFT 0 +#define MCDE_DSICMD1SYNC_DMA_MASK 0x00000FFF +#define MCDE_DSICMD1SYNC_DMA(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1SYNC, DMA, __x) +#define MCDE_DSICMD1SYNC_SW_SHIFT 16 +#define MCDE_DSICMD1SYNC_SW_MASK 0x0FFF0000 +#define MCDE_DSICMD1SYNC_SW(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1SYNC, SW, __x) +#define MCDE_DSIVID2SYNC 0x00000E8C +#define MCDE_DSIVID2SYNC_DMA_SHIFT 0 +#define MCDE_DSIVID2SYNC_DMA_MASK 0x00000FFF +#define MCDE_DSIVID2SYNC_DMA(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2SYNC, DMA, __x) +#define MCDE_DSIVID2SYNC_SW_SHIFT 16 +#define MCDE_DSIVID2SYNC_SW_MASK 0x0FFF0000 +#define MCDE_DSIVID2SYNC_SW(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2SYNC, SW, __x) +#define MCDE_DSICMD2SYNC 0x00000EAC +#define MCDE_DSICMD2SYNC_DMA_SHIFT 0 +#define MCDE_DSICMD2SYNC_DMA_MASK 0x00000FFF +#define MCDE_DSICMD2SYNC_DMA(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2SYNC, DMA, __x) +#define MCDE_DSICMD2SYNC_SW_SHIFT 16 +#define MCDE_DSICMD2SYNC_SW_MASK 0x0FFF0000 +#define MCDE_DSICMD2SYNC_SW(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2SYNC, SW, __x) +#define MCDE_DSIVID0CMDW 0x00000E10 +#define MCDE_DSIVID0CMDW_GROUPOFFSET 0x20 +#define MCDE_DSIVID0CMDW_CMDW_CONTINUE_SHIFT 0 +#define MCDE_DSIVID0CMDW_CMDW_CONTINUE_MASK 0x0000FFFF +#define MCDE_DSIVID0CMDW_CMDW_CONTINUE(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0CMDW, CMDW_CONTINUE, __x) +#define MCDE_DSIVID0CMDW_CMDW_START_SHIFT 16 +#define MCDE_DSIVID0CMDW_CMDW_START_MASK 0xFFFF0000 +#define MCDE_DSIVID0CMDW_CMDW_START(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0CMDW, CMDW_START, __x) +#define MCDE_DSICMD0CMDW 0x00000E30 +#define MCDE_DSICMD0CMDW_CMDW_CONTINUE_SHIFT 0 +#define MCDE_DSICMD0CMDW_CMDW_CONTINUE_MASK 0x0000FFFF +#define MCDE_DSICMD0CMDW_CMDW_CONTINUE(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0CMDW, CMDW_CONTINUE, __x) +#define MCDE_DSICMD0CMDW_CMDW_START_SHIFT 16 +#define MCDE_DSICMD0CMDW_CMDW_START_MASK 0xFFFF0000 +#define MCDE_DSICMD0CMDW_CMDW_START(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0CMDW, CMDW_START, __x) +#define MCDE_DSIVID1CMDW 0x00000E50 +#define MCDE_DSIVID1CMDW_CMDW_CONTINUE_SHIFT 0 +#define MCDE_DSIVID1CMDW_CMDW_CONTINUE_MASK 0x0000FFFF +#define MCDE_DSIVID1CMDW_CMDW_CONTINUE(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1CMDW, CMDW_CONTINUE, __x) +#define MCDE_DSIVID1CMDW_CMDW_START_SHIFT 16 +#define MCDE_DSIVID1CMDW_CMDW_START_MASK 0xFFFF0000 +#define MCDE_DSIVID1CMDW_CMDW_START(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1CMDW, CMDW_START, __x) +#define MCDE_DSICMD1CMDW 0x00000E70 +#define MCDE_DSICMD1CMDW_CMDW_CONTINUE_SHIFT 0 +#define MCDE_DSICMD1CMDW_CMDW_CONTINUE_MASK 0x0000FFFF +#define MCDE_DSICMD1CMDW_CMDW_CONTINUE(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1CMDW, CMDW_CONTINUE, __x) +#define MCDE_DSICMD1CMDW_CMDW_START_SHIFT 16 +#define MCDE_DSICMD1CMDW_CMDW_START_MASK 0xFFFF0000 +#define MCDE_DSICMD1CMDW_CMDW_START(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1CMDW, CMDW_START, __x) +#define MCDE_DSIVID2CMDW 0x00000E90 +#define MCDE_DSIVID2CMDW_CMDW_CONTINUE_SHIFT 0 +#define MCDE_DSIVID2CMDW_CMDW_CONTINUE_MASK 0x0000FFFF +#define MCDE_DSIVID2CMDW_CMDW_CONTINUE(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2CMDW, CMDW_CONTINUE, __x) +#define MCDE_DSIVID2CMDW_CMDW_START_SHIFT 16 +#define MCDE_DSIVID2CMDW_CMDW_START_MASK 0xFFFF0000 +#define MCDE_DSIVID2CMDW_CMDW_START(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2CMDW, CMDW_START, __x) +#define MCDE_DSICMD2CMDW 0x00000EB0 +#define MCDE_DSICMD2CMDW_CMDW_CONTINUE_SHIFT 0 +#define MCDE_DSICMD2CMDW_CMDW_CONTINUE_MASK 0x0000FFFF +#define MCDE_DSICMD2CMDW_CMDW_CONTINUE(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2CMDW, CMDW_CONTINUE, __x) +#define MCDE_DSICMD2CMDW_CMDW_START_SHIFT 16 +#define MCDE_DSICMD2CMDW_CMDW_START_MASK 0xFFFF0000 +#define MCDE_DSICMD2CMDW_CMDW_START(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2CMDW, CMDW_START, __x) +#define MCDE_DSIVID0DELAY0 0x00000E14 +#define MCDE_DSIVID0DELAY0_GROUPOFFSET 0x20 +#define MCDE_DSIVID0DELAY0_INTPKTDEL_SHIFT 0 +#define MCDE_DSIVID0DELAY0_INTPKTDEL_MASK 0x0000FFFF +#define MCDE_DSIVID0DELAY0_INTPKTDEL(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0DELAY0, INTPKTDEL, __x) +#define MCDE_DSICMD0DELAY0 0x00000E34 +#define MCDE_DSICMD0DELAY0_INTPKTDEL_SHIFT 0 +#define MCDE_DSICMD0DELAY0_INTPKTDEL_MASK 0x0000FFFF +#define MCDE_DSICMD0DELAY0_INTPKTDEL(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0DELAY0, INTPKTDEL, __x) +#define MCDE_DSIVID1DELAY0 0x00000E54 +#define MCDE_DSIVID1DELAY0_INTPKTDEL_SHIFT 0 +#define MCDE_DSIVID1DELAY0_INTPKTDEL_MASK 0x0000FFFF +#define MCDE_DSIVID1DELAY0_INTPKTDEL(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1DELAY0, INTPKTDEL, __x) +#define MCDE_DSICMD1DELAY0 0x00000E74 +#define MCDE_DSICMD1DELAY0_INTPKTDEL_SHIFT 0 +#define MCDE_DSICMD1DELAY0_INTPKTDEL_MASK 0x0000FFFF +#define MCDE_DSICMD1DELAY0_INTPKTDEL(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1DELAY0, INTPKTDEL, __x) +#define MCDE_DSIVID2DELAY0 0x00000E94 +#define MCDE_DSIVID2DELAY0_INTPKTDEL_SHIFT 0 +#define MCDE_DSIVID2DELAY0_INTPKTDEL_MASK 0x0000FFFF +#define MCDE_DSIVID2DELAY0_INTPKTDEL(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2DELAY0, INTPKTDEL, __x) +#define MCDE_DSICMD2DELAY0 0x00000EB4 +#define MCDE_DSICMD2DELAY0_INTPKTDEL_SHIFT 0 +#define MCDE_DSICMD2DELAY0_INTPKTDEL_MASK 0x0000FFFF +#define MCDE_DSICMD2DELAY0_INTPKTDEL(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2DELAY0, INTPKTDEL, __x) +#define MCDE_DSIVID0DELAY1 0x00000E18 +#define MCDE_DSIVID0DELAY1_GROUPOFFSET 0x20 +#define MCDE_DSIVID0DELAY1_TEREQDEL_SHIFT 0 +#define MCDE_DSIVID0DELAY1_TEREQDEL_MASK 0x00000FFF +#define MCDE_DSIVID0DELAY1_TEREQDEL(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0DELAY1, TEREQDEL, __x) +#define MCDE_DSIVID0DELAY1_FRAMESTARTDEL_SHIFT 16 +#define MCDE_DSIVID0DELAY1_FRAMESTARTDEL_MASK 0x00FF0000 +#define MCDE_DSIVID0DELAY1_FRAMESTARTDEL(__x) \ + MCDE_VAL2REG(MCDE_DSIVID0DELAY1, FRAMESTARTDEL, __x) +#define MCDE_DSICMD0DELAY1 0x00000E38 +#define MCDE_DSICMD0DELAY1_TEREQDEL_SHIFT 0 +#define MCDE_DSICMD0DELAY1_TEREQDEL_MASK 0x00000FFF +#define MCDE_DSICMD0DELAY1_TEREQDEL(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0DELAY1, TEREQDEL, __x) +#define MCDE_DSICMD0DELAY1_FRAMESTARTDEL_SHIFT 16 +#define MCDE_DSICMD0DELAY1_FRAMESTARTDEL_MASK 0x00FF0000 +#define MCDE_DSICMD0DELAY1_FRAMESTARTDEL(__x) \ + MCDE_VAL2REG(MCDE_DSICMD0DELAY1, FRAMESTARTDEL, __x) +#define MCDE_DSIVID1DELAY1 0x00000E58 +#define MCDE_DSIVID1DELAY1_TEREQDEL_SHIFT 0 +#define MCDE_DSIVID1DELAY1_TEREQDEL_MASK 0x00000FFF +#define MCDE_DSIVID1DELAY1_TEREQDEL(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1DELAY1, TEREQDEL, __x) +#define MCDE_DSIVID1DELAY1_FRAMESTARTDEL_SHIFT 16 +#define MCDE_DSIVID1DELAY1_FRAMESTARTDEL_MASK 0x00FF0000 +#define MCDE_DSIVID1DELAY1_FRAMESTARTDEL(__x) \ + MCDE_VAL2REG(MCDE_DSIVID1DELAY1, FRAMESTARTDEL, __x) +#define MCDE_DSICMD1DELAY1 0x00000E78 +#define MCDE_DSICMD1DELAY1_TEREQDEL_SHIFT 0 +#define MCDE_DSICMD1DELAY1_TEREQDEL_MASK 0x00000FFF +#define MCDE_DSICMD1DELAY1_TEREQDEL(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1DELAY1, TEREQDEL, __x) +#define MCDE_DSICMD1DELAY1_FRAMESTARTDEL_SHIFT 16 +#define MCDE_DSICMD1DELAY1_FRAMESTARTDEL_MASK 0x00FF0000 +#define MCDE_DSICMD1DELAY1_FRAMESTARTDEL(__x) \ + MCDE_VAL2REG(MCDE_DSICMD1DELAY1, FRAMESTARTDEL, __x) +#define MCDE_DSIVID2DELAY1 0x00000E98 +#define MCDE_DSIVID2DELAY1_TEREQDEL_SHIFT 0 +#define MCDE_DSIVID2DELAY1_TEREQDEL_MASK 0x00000FFF +#define MCDE_DSIVID2DELAY1_TEREQDEL(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2DELAY1, TEREQDEL, __x) +#define MCDE_DSIVID2DELAY1_FRAMESTARTDEL_SHIFT 16 +#define MCDE_DSIVID2DELAY1_FRAMESTARTDEL_MASK 0x00FF0000 +#define MCDE_DSIVID2DELAY1_FRAMESTARTDEL(__x) \ + MCDE_VAL2REG(MCDE_DSIVID2DELAY1, FRAMESTARTDEL, __x) +#define MCDE_DSICMD2DELAY1 0x00000EB8 +#define MCDE_DSICMD2DELAY1_TEREQDEL_SHIFT 0 +#define MCDE_DSICMD2DELAY1_TEREQDEL_MASK 0x00000FFF +#define MCDE_DSICMD2DELAY1_TEREQDEL(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2DELAY1, TEREQDEL, __x) +#define MCDE_DSICMD2DELAY1_FRAMESTARTDEL_SHIFT 16 +#define MCDE_DSICMD2DELAY1_FRAMESTARTDEL_MASK 0x00FF0000 +#define MCDE_DSICMD2DELAY1_FRAMESTARTDEL(__x) \ + MCDE_VAL2REG(MCDE_DSICMD2DELAY1, FRAMESTARTDEL, __x) |