/*
* drivers/video/pnx4008/sdum.c
*
* Display Update Master support
*
* Authors: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com>
* Vitaly Wool <vitalywool@gmail.com>
* Based on Philips Semiconductors's code
*
* Copyrght (c) 2005-2006 MontaVista Software, Inc.
* Copyright (c) 2005 Philips Semiconductors
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/gfp.h>
#include <asm/uaccess.h>
#include <mach/gpio.h>
#include "sdum.h"
#include "fbcommon.h"
#include "dum.h"
/* Framebuffers we have */
static struct pnx4008_fb_addr {
int fb_type;
long addr_offset;
long fb_length;
} fb_addr[] = {
[0] = {
FB_TYPE_YUV, 0, 0xB0000
},
[1] = {
FB_TYPE_RGB, 0xB0000, 0x50000
},
};
static struct dum_data {
u32 lcd_phys_start;
u32 lcd_virt_start;
u32 slave_phys_base;
u32 *slave_virt_base;
int fb_owning_channel[MAX_DUM_CHANNELS];
struct dumchannel_uf chan_uf_store[MAX_DUM_CHANNELS];
} dum_data;
/* Different local helper functions */
static u32 nof_pixels_dx(struct dum_ch_setup *ch_setup)
{
return (ch_setup->xmax - ch_setup->xmin + 1);
}
static u32 nof_pixels_dy(struct dum_ch_setup *ch_setup)
{
return (ch_setup->ymax - ch_setup->ymin + 1);
}
static u32 nof_pixels_dxy(struct dum_ch_setup *ch_setup)
{
return (nof_pixels_dx(ch_setup) * nof_pixels_dy(ch_setup));
}
static u32 nof_bytes(struct dum_ch_setup *ch_setup)
{
u32 r = nof_pixels_dxy(ch_setup);
switch (ch_setup->format) {
case RGB888:
case RGB666:
r *= 4;
break;
default:
r *= 2;
break;
}
return r;
}
static u32 build_command(int disp_no, u32 reg, u32 val)
{
return ((disp_no << 26) | BIT(25) | (val << 16) | (disp_no << 10) |
(reg << 0));
}
static u32 build_double_index(int disp_no, u32 val)
{
return ((disp_no << 26) | (val << 16) | (disp_no << 10) | (val << 0));
}
static void build_disp_window(struct dum_ch_setup * ch_setup, struct disp_window * dw)
{
dw->ymin = ch_setup->ymin;
dw->ymax = ch_setup->ymax;
dw->xmin_l = ch_setup->xmin & 0xFF;
dw->xmin_h = (ch_setup->xmin & BIT(8)) >> 8;
dw->xmax_l = ch_setup->xmax & 0xFF;
dw->xmax_h = (ch_setup->xmax & BIT(8)) >> 8;
}
static int put_channel(struct dumchannel chan)
{
int i = chan.channelnr;
if (i < 0 || i > MAX_DUM_CHANNELS)
return -EINVAL;
else {
DUM_CH_MIN(i) = chan.dum_ch_min;
DUM_CH_MAX(i) = chan.dum_ch_max;
DUM_CH_CONF(i) = chan.dum_ch_conf;
DUM_CH_CTRL(i) = chan.dum_ch_ctrl;
}
return 0;
}
static void clear_channel(int channr)
{
struct dumchannel chan;
chan.channelnr = channr;
chan.dum_ch_min = 0;
chan.dum_ch_max = 0;
chan.dum_ch_conf = 0;
chan.dum_ch_ctrl = 0;
put_channel(chan);
}
static int put_cmd_string(struct cmdstring cmds)
{
u16 *cmd_str_virtaddr;
u32 *cmd_ptr0_virtaddr;
u32 cmd_str_physaddr;
int i = cmds.channelnr;
if (i < 0 || i > MAX_DUM_CHANNELS)
return -EINVAL;
else if ((cmd_ptr0_virtaddr =
(int *)ioremap_nocache(DUM_COM_BASE,
sizeof(int) * MAX_DUM_CHANNELS)) ==
NULL)
return -EIOREMAPFAILED;
else {
cmd_str_physaddr = ioread32(&cmd_ptr0_virtaddr[cmds.channelnr]);
if ((cmd_str_virtaddr =
(u16 *) ioremap_nocache(cmd_str_physaddr,
sizeof(cmds))) == NULL) {
iounmap(cmd_ptr0_virtaddr);
return -EIOREMAPFAILED;
} else {
int t;
for (t = 0; t < 8; t++)
iowrite16(*((u16 *)&cmds.prestringlen + t),
cmd_str_virtaddr