diff options
author | Kevin Hilman <khilman@deeprootsystems.com> | 2010-05-24 10:13:40 -0700 |
---|---|---|
committer | Kevin Hilman <khilman@deeprootsystems.com> | 2010-05-24 10:13:40 -0700 |
commit | fcf114341a9117d90a3764c7ce4c0f98965a0b03 (patch) | |
tree | fa4a60b8ea7b73821f3bacc8cc8a663c2704b1ea | |
parent | 779d33afab276e5b69e2bea012c6c421924f79da (diff) | |
parent | b6d931f2f5529b5c8b478a9a9ab8ba8cfdacf757 (diff) |
Merge branch 'davinci-orphaned' into davinci-reset
-rw-r--r-- | arch/arm/mach-davinci/board-dm365-evm.c | 3 | ||||
-rw-r--r-- | drivers/input/misc/Kconfig | 9 | ||||
-rw-r--r-- | drivers/input/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/misc/dm365evm_keys.c | 323 | ||||
-rw-r--r-- | drivers/video/Kconfig | 15 | ||||
-rw-r--r-- | drivers/video/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/davincifb.c | 1734 | ||||
-rw-r--r-- | include/video/davincifb.h | 442 | ||||
-rw-r--r-- | sound/soc/davinci/davinci-sffsdr.c | 19 |
9 files changed, 2540 insertions, 7 deletions
diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index 98814e6a5987..fdb073eebf86 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -179,6 +179,9 @@ static struct snd_platform_data dm365_evm_snd_data; static struct i2c_board_info i2c_info[] = { { + I2C_BOARD_INFO("dm365evm_keys", 0x25), + }, + { I2C_BOARD_INFO("24c256", 0x50), .platform_data = &eeprom_info, }, diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 23140a3bb8e0..b28168be9a5c 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -311,6 +311,15 @@ config INPUT_DM355EVM To compile this driver as a module, choose M here: the module will be called dm355evm_keys. +config INPUT_DM365EVM + tristate "TI DaVinci DM365 EVM IR Remote" + depends on MACH_DAVINCI_DM365_EVM + help + Supports the IR remote used with the DM365 EVM board. + + To compile this driver as a module, choose M here: the + module will be called dm365evm_keys. + config INPUT_BFIN_ROTARY tristate "Blackfin Rotary support" depends on BF54x || BF52x diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 7e95a5d474dc..f638a70bf2a3 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o obj-$(CONFIG_INPUT_CM109) += cm109.o obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o +obj-$(CONFIG_INPUT_DM365EVM) += dm365evm_keys.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o diff --git a/drivers/input/misc/dm365evm_keys.c b/drivers/input/misc/dm365evm_keys.c new file mode 100644 index 000000000000..26df358be9f3 --- /dev/null +++ b/drivers/input/misc/dm365evm_keys.c @@ -0,0 +1,323 @@ +/* + * dm365evm_keys.c - support IR remote on DM365 EVM board + * + * Copyright (c) 2009 by David Brownell + * + * 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. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/slab.h> + +/* + * The MSP430 firmware on the DM365 EVM monitors an IR receptor used for + * the remote control. When any key is pressed, or its autorepeat kicks + * in, an event is sent. This driver read those events from the small + * event queue and reports them. + * + * Compared to the DM355 EVM: the MSP firmware does *only* IR. So this + * driver is simpler, and doesn't even need to use the MFD model. + * + * Note that physically there can only be one of these devices. + * + * This driver was tested with firmware revision 0xA1 (beta board). + */ +struct dm365evm_keys { + struct input_dev *input; + struct i2c_client *i2c; +}; + +#define DM365EVM_MSP_FIRMREV 0 +#define DM365EVM_MSP_INPUT_LOW 1 +#define DM365EVM_MSP_INPUT_HIGH 2 +#define DM365EVM_MSP_INPUT_COUNT 3 +#define DM365EVM_MSP_0x43 4 + +#define MSP430_GPIO 0 + +/* These initial keycodes can be remapped by dm365evm_setkeycode(). */ +static struct { + u16 event; + u16 keycode; +} dm365evm_keys[] = { + + /* + * IR buttons ... codes assigned to match the universal remote + * provided with the EVM (Philips PM4S) using DVD code 0020. + * + * These event codes match firmware documentation, but other + * remote controls could easily send more RC5-encoded events. + * The PM4S manual was used in several cases to help select + * a keycode reflecting the intended usage. + * + * RC5 codes are 14 bits, with two start bits (0x3 prefix) + * and a toggle bit (masked out below). + */ + { 0x300c, KEY_POWER, }, /* NOTE: docs omit this */ + { 0x3000, KEY_NUMERIC_0, }, + { 0x3001, KEY_NUMERIC_1, }, + { 0x3002, KEY_NUMERIC_2, }, + { 0x3003, KEY_NUMERIC_3, }, + { 0x3004, KEY_NUMERIC_4, }, + { 0x3005, KEY_NUMERIC_5, }, + { 0x3006, KEY_NUMERIC_6, }, + { 0x3007, KEY_NUMERIC_7, }, + { 0x3008, KEY_NUMERIC_8, }, + { 0x3009, KEY_NUMERIC_9, }, + { 0x3022, KEY_ENTER, }, + { 0x30ec, KEY_MODE, }, /* "tv/vcr/..." */ + { 0x300f, KEY_SELECT, }, /* "info" */ + { 0x3020, KEY_CHANNELUP, }, /* "up" */ + { 0x302e, KEY_MENU, }, /* "in/out" */ + { 0x3011, KEY_VOLUMEDOWN, }, /* "left" */ + { 0x300d, KEY_MUTE, }, /* "ok" */ + { 0x3010, KEY_VOLUMEUP, }, /* "right" */ + { 0x301e, KEY_SUBTITLE, }, /* "cc" */ + { 0x3021, KEY_CHANNELDOWN, }, /* "down" */ + { 0x3022, KEY_PREVIOUS, }, + { 0x3026, KEY_SLEEP, }, + { 0x3172, KEY_REWIND, }, + { 0x3175, KEY_PLAY, }, + { 0x3174, KEY_FASTFORWARD, }, + { 0x3177, KEY_RECORD, }, + { 0x3176, KEY_STOP, }, + { 0x3169, KEY_PAUSE, }, + + /* NOTE: SW22, a pushbutton next to the IR sensor, is also + * wired to the MSP430 but is currently ignored; some other + * I/O pins are likewise wired but ignored. + */ +}; + +static irqreturn_t dm365evm_keys_irq(int irq, void *_keys) +{ + struct dm365evm_keys *keys = _keys; + + /* For simplicity we ignore INPUT_COUNT and just read + * events until the GPIO stops signaling data ready. + */ + while (gpio_get_value(MSP430_GPIO) == 0) { + static u16 last_event; + u16 event; + int keycode; + int i; + + /* Read low, then high bytes; reading the high byte + * removes an entry from the input buffer. + */ + event = i2c_smbus_read_word_data(keys->i2c, + DM365EVM_MSP_INPUT_LOW); + if (event < 0) { + dev_dbg(&keys->i2c->dev, "input err %d\n", event); + break; + } + event = event; + + /* Press and release a button: two events, same code. + * Press and hold (autorepeat), then release: N events + * (N > 2), same code. For RC5 buttons the toggle bits + * distinguish (for example) "1-autorepeat" from "1 1"; + * but PCB buttons don't support that bit. + * + * So we must synthesize release events. We do that by + * mapping events to a press/release event pair; then + * to avoid adding extra events, skip the second event + * of each pair. + */ + if (event == last_event) { + last_event = 0; + continue; + } + last_event = event; + + /* ignore the RC5 toggle bit */ + event &= ~0x0800; + + /* find the key, or leave it as unknown */ + keycode = KEY_UNKNOWN; + for (i = 0; i < ARRAY_SIZE(dm365evm_keys); i++) { + if (dm365evm_keys[i].event != event) + continue; + keycode = dm365evm_keys[i].keycode; + break; + } + dev_dbg(&keys->i2c->dev, + "input event 0x%04x--> keycode %d\n", + event, keycode); + + /* report press + release */ + input_report_key(keys->input, keycode, 1); + input_sync(keys->input); + input_report_key(keys->input, keycode, 0); + input_sync(keys->input); + } + return IRQ_HANDLED; +} + +/* + * Since we talk to the MSP using I2C, we need to delegate all real + * IRQ handling work to some task context. We'll use an IRQ thread. + */ +static irqreturn_t dm365evm_keys_hardirq(int irq, void *_keys) +{ + return IRQ_WAKE_THREAD; +} + +static int dm365evm_setkeycode(struct input_dev *dev, int index, int keycode) +{ + u16 old_keycode; + unsigned i; + + if (((unsigned)index) >= ARRAY_SIZE(dm365evm_keys)) + return -EINVAL; + + old_keycode = dm365evm_keys[index].keycode; + dm365evm_keys[index].keycode = keycode; + set_bit(keycode, dev->keybit); + + for (i = 0; i < ARRAY_SIZE(dm365evm_keys); i++) { + if (dm365evm_keys[index].keycode == old_keycode) + goto done; + } + clear_bit(old_keycode, dev->keybit); +done: + return 0; +} + +static int dm365evm_getkeycode(struct input_dev *dev, int index, int *keycode) +{ + if (((unsigned)index) >= ARRAY_SIZE(dm365evm_keys)) + return -EINVAL; + + return dm365evm_keys[index].keycode; +} + +/*----------------------------------------------------------------------*/ + +static int __devinit +dm365evm_keys_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + struct dm365evm_keys *keys; + struct input_dev *input; + int status; + int i; + + status = gpio_request(MSP430_GPIO, id->name); + if (status < 0) + return status; + + status = gpio_direction_input(MSP430_GPIO); + if (status < 0) { + gpio_free(MSP430_GPIO); + return status; + } + + /* allocate instance struct and input dev */ + keys = kzalloc(sizeof *keys, GFP_KERNEL); + input = input_allocate_device(); + if (!keys || !input) { + status = -ENOMEM; + goto fail1; + } + + keys->i2c = i2c; + keys->input = input; + + input_set_drvdata(input, keys); + + input->name = "DM365 EVM Controls"; + input->phys = "dm365evm/input0"; + input->dev.parent = &i2c->dev; + + input->id.bustype = BUS_I2C; + input->id.product = 0x0365; + input->id.version = i2c_smbus_read_byte_data(i2c, + DM365EVM_MSP_FIRMREV); + + input->evbit[0] = BIT(EV_KEY); + for (i = 0; i < ARRAY_SIZE(dm365evm_keys); i++) + __set_bit(dm365evm_keys[i].keycode, input->keybit); + + input->setkeycode = dm365evm_setkeycode; + input->getkeycode = dm365evm_getkeycode; + + /* FIXME: flush the event queue */ + + status = request_threaded_irq(gpio_to_irq(MSP430_GPIO), + dm365evm_keys_hardirq, dm365evm_keys_irq, + IRQF_TRIGGER_FALLING, + id->name, keys); + if (status < 0) + goto fail1; + + /* register */ + status = input_register_device(input); + if (status < 0) + goto fail2; + + i2c_set_clientdata(i2c, keys); + + return 0; + +fail2: + free_irq(gpio_to_irq(MSP430_GPIO), keys); +fail1: + input_free_device(input); + kfree(keys); + gpio_free(MSP430_GPIO); + dev_err(&i2c->dev, "can't register, err %d\n", status); + + return status; +} + +static int __devexit dm365evm_keys_remove(struct i2c_client *i2c) +{ + struct dm365evm_keys *keys = i2c_get_clientdata(i2c); + + free_irq(gpio_to_irq(MSP430_GPIO), keys); + input_unregister_device(keys->input); + kfree(keys); + + gpio_free(MSP430_GPIO); + + return 0; +} + +/* REVISIT: add suspend/resume when DaVinci supports it. The IRQ should + * be able to wake up the system. When device_may_wakeup(&i2c->dev), call + * enable_irq_wake() on suspend, and disable_irq_wake() on resume. + */ + +static const struct i2c_device_id ids[] = { + { .name = "dm365evm_keys", }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, ids); + +static struct i2c_driver dm365evm_keys_driver = { + .driver.name = "dm365evm_keys", + .id_table = ids, + .probe = dm365evm_keys_probe, + .remove = __devexit_p(dm365evm_keys_remove), +}; + +static int __init dm365evm_keys_init(void) +{ + return i2c_add_driver(&dm365evm_keys_driver); +} +module_init(dm365evm_keys_init); + +static void __exit dm365evm_keys_exit(void) +{ + i2c_del_driver(&dm365evm_keys_driver); +} +module_exit(dm365evm_keys_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6e16244f3ed1..29aa5d61ce06 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -2023,6 +2023,21 @@ config FB_IBM_GXT4500 Say Y here to enable support for the IBM GXT4500P display adaptor, found on some IBM System P (pSeries) machines. +config FB_DAVINCI + bool "Davinci Framebuffer support" + depends on FB && ARCH_DAVINCI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + This is the frame buffer device driver for the DaVinci video + hardware found on the TI DaVinci EVM. If + unsure, say N. + +config FB_VIRTUAL + tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" + depends on FB + config FB_PS3 tristate "PS3 GPU framebuffer driver" depends on FB && PS3_PS3AV diff --git a/drivers/video/Makefile b/drivers/video/Makefile index ddc2af2ba45b..d5ebc2415ba4 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -143,6 +143,7 @@ obj-$(CONFIG_FB_BFIN_LQ035Q1) += bfin-lq035q1-fb.o obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o obj-$(CONFIG_FB_MX3) += mx3fb.o obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o +obj-$(CONFIG_FB_DAVINCI) += davincifb.o # the test framebuffer is last obj-$(CONFIG_FB_VIRTUAL) += vfb.o diff --git a/drivers/video/davincifb.c b/drivers/video/davincifb.c new file mode 100644 index 000000000000..1344be74a284 --- /dev/null +++ b/drivers/video/davincifb.c @@ -0,0 +1,1734 @@ +/* + * drivers/video/davincifb.c + * + * Framebuffer driver for Texas Instruments DaVinci display controller. + * + * Copyright (C) 2006 Texas Instruments, Inc. + * Rishi Bhattacharya <support@ti.com> + * + * Leveraged from the framebuffer driver for OMAP24xx + * written by Andy Lowe (source@mvista.com) + * Copyright (C) 2004 MontaVista Software, Inc. + * + * 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/slab.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> + +#include <asm/irq.h> +#include <asm/uaccess.h> + +#include <video/davincifb.h> +#include <asm/system.h> + +#define MODULE_NAME "davincifb" + +/* Output Format Selection */ +#define MULTIPLE_BUFFERING 1 + +#ifdef MULTIPLE_BUFFERING +#define DOUBLE_BUF 2 +#define TRIPLE_BUF 3 +#else +#define DOUBLE_BUF 1 +#define TRIPLE_BUF 1 +#endif + +/* + * display controller register I/O routines + */ +static __inline__ u32 dispc_reg_in(u32 reg) +{ + return ioread32(IO_ADDRESS(reg)); +} +static __inline__ u32 dispc_reg_out(u32 reg, u32 val) +{ + iowrite32(val, IO_ADDRESS(reg)); + return (val); +} +static __inline__ u32 dispc_reg_merge(u32 reg, u32 val, u32 mask) +{ + u32 new_val = (ioread32(IO_ADDRESS(reg)) & ~mask) | (val & mask); + + iowrite32(new_val, IO_ADDRESS(reg)); + return (new_val); +} + +/* There are 4 framebuffers, each represented by an fb_info and + * a dm_win_info structure */ +#define OSD0_FBNAME "dm_osd0_fb" +#define OSD1_FBNAME "dm_osd1_fb" +#define VID0_FBNAME "dm_vid0_fb" +#define VID1_FBNAME "dm_vid1_fb" + +/* usage: if (is_win(info->fix.id, OSD0)) ... */ +#define is_win(name, x) ((strcmp(name, x ## _FBNAME) == 0) ? 1 : 0) + +struct dm_win_info { + struct fb_info info; + + /* X and Y position */ + unsigned int x, y; + + /* framebuffer area */ + dma_addr_t fb_base_phys; + unsigned long fb_base; + unsigned long fb_size; + + u32 pseudo_palette[17]; + + /* flag to identify if framebuffer area is fixed already or not */ + int alloc_fb_mem; + unsigned long sdram_address; + struct dm_info *dm; +}; + +static struct dm_info { + struct dm_win_info *osd0; + struct dm_win_info *osd1; + struct dm_win_info *vid0; + struct dm_win_info *vid1; + + /* to map the registers */ + dma_addr_t mmio_base_phys; + unsigned long mmio_base; + unsigned long mmio_size; + + wait_queue_head_t vsync_wait; + unsigned long vsync_cnt; + int timeout; + + /* this is the function that configures the output device (NTSC/PAL/LCD) + * for the required output format (composite/s-video/component/rgb) + */ + void (*output_device_config) (int on); + + struct device *dev; +} dm_static; +static struct dm_info *dm = &dm_static; + +static struct fb_ops davincifb_ops; + +#define BASEX 0x80 +#define BASEY 0x12 + +#define DISP_XRES 720 +#define DISP_YRES 480 +#define DISP_MEMY 576 + +/* Random value chosen for now. Should be within the panel's supported range */ +#define LCD_PANEL_CLOCK 180000 + +/* All window widths have to be rounded up to a multiple of 32 bytes */ + +/* The OSD0 window has to be always within VID0. Plus, since it is in RGB565 + * mode, it _cannot_ overlap with VID1. + * For defaults, we are setting the OSD0 window to be displayed in the top + * left quadrant of the screen, and the VID1 in the bottom right quadrant. + * So the default 'xres' and 'yres' are set to half of the screen width and + * height respectively. Note however that the framebuffer size is allocated + * for the full screen size so the user can change the 'xres' and 'yres' by + * using the FBIOPUT_VSCREENINFO ioctl within the limits of the screen size. + */ +#define round_32(width) ((((width) + 31) / 32) * 32 ) + +#define OSD0_XRES round_32((DISP_XRES)*16/8) * 8/16 /* pixels */ +#define OSD0_YRES DISP_YRES +#define OSD0_FB_PHY 0 +#define OSD0_FB_SIZE (round_32((DISP_XRES)*16/8) * DISP_MEMY * DOUBLE_BUF) + + /* 16 bpp, Double buffered */ +static struct fb_var_screeninfo osd0_default_var = { + .xres = OSD0_XRES, + .yres = OSD0_YRES, + .xres_virtual = OSD0_XRES, + .yres_virtual = OSD0_YRES * DOUBLE_BUF, + .xoffset = 0, + .yoffset = 0, + .bits_per_pixel = 16, + .grayscale = 0, + .red = {11, 5, 0}, + .green = {5, 6, 0}, + .blue = {0, 5, 0}, + .transp = {0, 0, 0}, + .nonstd = 0, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .accel_flags = 0, + .pixclock = LCD_PANEL_CLOCK, /* picoseconds */ + .left_margin = 40, /* pixclocks */ + .right_margin = 4, /* pixclocks */ + .upper_margin = 8, /* line clocks */ + .lower_margin = 2, /* line clocks */ + .hsync_len = 4, /* pixclocks */ + .vsync_len = 2, /* line clocks */ + .sync = 0, + .vmode = FB_VMODE_INTERLACED, +}; + +/* Using the full screen for OSD1 by default */ +#define OSD1_XRES round_32(DISP_XRES*4/8) * 8/4 /* pixels */ +#define OSD1_YRES DISP_YRES +#define OSD1_FB_PHY 0 +#define OSD1_FB_SIZE (round_32(DISP_XRES*4/8) * DISP_MEMY * DOUBLE_BUF) + +static struct fb_var_screeninfo osd1_default_var = { + .xres = DISP_XRES, + .yres = OSD1_YRES, + .xres_virtual = OSD1_XRES, + .yres_virtual = OSD1_YRES * DOUBLE_BUF, + .xoffset = 0, + .yoffset = 0, + .bits_per_pixel = 4, + .activate = FB_ACTIVATE_NOW, + .accel_flags = 0, + .pixclock = LCD_PANEL_CLOCK, /* picoseconds */ + .vmode = FB_VMODE_INTERLACED, +}; + +/* Using the full screen for OSD0 by default */ +#define VID0_XRES round_32(DISP_XRES*16/8) * 8/16 /* pixels */ +#define VID0_YRES DISP_YRES +#define VID0_FB_PHY 0 +#define VID0_FB_SIZE (round_32(DISP_XRES*16/8) * DISP_MEMY * TRIPLE_BUF) +static struct fb_var_screeninfo vid0_default_var = { + .xres = VID0_XRES, + .yres = VID0_YRES, + .xres_virtual = VID0_XRES, + .yres_virtual = VID0_YRES * TRIPLE_BUF, + .xoffset = 0, + .yoffset = 0, + .bits_per_pixel = 16, + .activate = FB_ACTIVATE_NOW, + .accel_flags = 0, + .pixclock = LCD_PANEL_CLOCK, /* picoseconds */ + .vmode = FB_VMODE_INTERLACED, +}; + +/* Using the bottom right quadrant of the screen screen for VID1 by default, + * but keeping the framebuffer allocated for the full screen, so the user can + * change the 'xres' and 'yres' later using the FBIOPUT_VSCREENINFO ioctl. + */ +#define VID1_BPP 16 /* Video1 can be in YUV or RGB888 format */ +#define VID1_XRES round_32(DISP_XRES*16/8) * 8/16 /* pixels */ +#define VID1_YRES DISP_YRES +#define VID1_FB_PHY 0 +#define VID1_FB_SIZE (round_32(DISP_XRES*16/8) * DISP_MEMY * TRIPLE_BUF) +static struct fb_var_screeninfo vid1_default_var = { + .xres = VID1_XRES, + .yres = VID1_YRES, + .xres_virtual = VID1_XRES, + .yres_virtual = VID1_YRES * TRIPLE_BUF, + .xoffset = 0, + .yoffset = 0, + .bits_per_pixel = VID1_BPP, + .activate = FB_ACTIVATE_NOW, + .accel_flags = 0, + .pixclock = LCD_PANEL_CLOCK, /* picoseconds */ + .vmode = FB_VMODE_INTERLACED, +}; + +#define x_pos(w) ((w)->x) +#define y_pos(w) ((w)->y) + +static struct dmparams_t { + u8 output; + u8 format; + u8 windows; /* bitmap flag based on VID0, VID1, OSD0, OSD1 + * definitions in header file */ + u32 vid0_xres; + u32 vid0_yres; + u32 vid0_xpos; + u32 vid0_ypos; + + u32 vid1_xres; + u32 vid1_yres; + u32 vid1_xpos; + u32 vid1_ypos; + + u32 osd0_xres; + u32 osd0_yres; + u32 osd0_xpos; + u32 osd0_ypos; + + u32 osd1_xres; + u32 osd1_yres; + u32 osd1_xpos; + u32 osd1_ypos; +} dmparams = { + NTSC, /* output */ + COMPOSITE, /* format */ + (1 << VID0) | (1 << VID1) | (1 << OSD0) | (1 << OSD1), + /* windows registered */ + 720, 480, 0, 0, /* vid0 size and position */ + 720, 480, 0, 0, /* vid1 size and position */ + 720, 480, 0, 0, /* osd0 size and position */ + 720, 480, 0, 0, /* osd1 size and position */ +}; + +/* Must do checks against the limits of the output device */ +static int davincifb_venc_check_mode(const struct dm_win_info *w, + const struct fb_var_screeninfo *var) +{ + return 0; +} + +static void set_sdram_params(char *id, u32 addr, u32 line_length); +static irqreturn_t davincifb_isr(int irq, void *arg) +{ + struct dm_info *dm = (struct dm_info *)arg; + unsigned long addr=0; + + if ((dispc_reg_in(VENC_VSTAT) & 0x00000010) == 0x10) { + xchg(&addr, dm->osd0->sdram_address); + if (addr) { + set_sdram_params(dm->osd0->info.fix.id, + dm->osd0->sdram_address, + dm->osd0->info.fix.line_length); + dm->osd0->sdram_address = 0; + } + addr = 0; + xchg(&addr, dm->osd1->sdram_address); + if (addr) { + set_sdram_params(dm->osd1->info.fix.id, + dm->osd1->sdram_address, + dm->osd1->info.fix.line_length); + dm->osd1->sdram_address = 0; + } + addr = 0; + xchg(&addr, dm->vid0->sdram_address); + if (addr) { + set_sdram_params(dm->vid0->info.fix.id, + dm->vid0->sdram_address, + dm->vid0->info.fix.line_length); + dm->vid0->sdram_address = 0; + } + addr = 0; + xchg(&addr, dm->vid1->sdram_address); + if (addr) { + set_sdram_params(dm->vid1->info.fix.id, + dm->vid1->sdram_address, + dm->vid1->info.fix.line_length); + dm->vid1->sdram_address = 0; + } + return IRQ_HANDLED; + } else { + ++dm->vsync_cnt; + wake_up_interruptible(&dm->vsync_wait); + return IRQ_HANDLED; + } + + return IRQ_HANDLED; +} + +/* Wait for a vsync interrupt. This routine sleeps so it can only be called + * from process context. + */ +static int davincifb_wait_for_vsync(struct dm_win_info *w) +{ + struct dm_info *dm = w->dm; + wait_queue_t wq; + unsigned long cnt; + int ret; + + init_waitqueue_entry(&wq, current); + + cnt = dm->vsync_cnt; + ret = wait_event_interruptible_timeout(dm->vsync_wait, + cnt != dm->vsync_cnt, + dm->timeout); + if (ret < 0) + return (ret); + if (ret == 0) + return (-ETIMEDOUT); + + return (0); +} + +/* Sets a uniform attribute value over a rectangular area on the attribute + * window. The attribute value (0 to 7) is passed through the fb_fillrect's + * color parameter. + */ +static int davincifb_set_attr_blend(struct fb_fillrect *r) +{ + struct fb_info *info = &dm->osd1->info; + struct fb_var_screeninfo *var = &dm->osd1->info.var; + unsigned long start = 0; + u8 blend; + u32 width_bytes; + + if (r->dx + r->width > var->xres_virtual) + return -EINVAL; + if (r->dy + r->height > var->yres_virtual) + return -EINVAL; + if (r->color < 0 || r->color > 7) + return -EINVAL; + + /* since bits_per_pixel = 4, this will truncate the width if it is + * not even. Similarly r->dx will be rounded down to an even pixel. + * ... Do we want to return an error otherwise? + */ + width_bytes = r->width * var->bits_per_pixel / 8; + start = dm->osd1->fb_base + r->dy * info->fix.line_length + + r->dx * var->bits_per_pixel / 8; + + blend = (((u8) r->color & 0xf) << 4) | ((u8) r->color); + while (r->height--) { + start += info->fix.line_length; + memset((void *)start, blend, width_bytes); + } + + return 0; +} + +/* These position parameters are given through fb_var_screeninfo. + * xp = var.reserved[0], yp = var.reserved[1], + * xl = var.xres, yl = var.yres + */ +static void set_win_position(char *id, u32 xp, u32 yp, u32 xl, u32 yl) +{ + int i = 0; + + if (is_win(id, VID0)) { + i = 0; + } else if (is_win(id, VID1)) { + i = 1; + } else if (is_win(id, OSD0)) { + i = 2; + } else if (is_win(id, OSD1)) { + i = 3; + } + + dispc_reg_out(OSD_WINXP(i), xp); + dispc_reg_out(OSD_WINYP(i), yp); + dispc_reg_out(OSD_WINXL(i), xl); + dispc_reg_out(OSD_WINYL(i), yl); +} + +static inline void get_win_position(struct dm_win_info *w, + u32 * xp, u32 * yp, u32 * xl, u32 * yl) +{ + struct fb_var_screeninfo *v = &w->info.var; + + *xp = x_pos(w); + *yp = y_pos(w); + *xl = v->xres; + *yl = v->yres; +} + +/* Returns 1 if the windows overlap, 0 otherwise */ +static int window_overlap(struct dm_win_info *w, u32 xp, u32 yp, u32 xl, u32 yl) +{ + u32 _xp = 0, _yp = 0, _xl = 0, _yl = 0; + +#define OVERLAP(x1, y1, x2, y2, x3, y3, x4, y4) \ +(!( ((x1)<(x3) && (x2)<(x3)) || ((x1)>(x4) && (x2)>(x4)) || \ + ((y1)<(y3) && (y2)<(y3)) || ((y1)>(y4) && (y2)>(y4)) ) \ +) + + if (!w) + return (0); + + get_win_position(w, &_xp, &_yp, &_xl, &_yl); + + return (OVERLAP(xp, yp, xp + xl, yp + yl, + _xp, _yp, _xp + _xl, _yp + _yl)); +#undef OVERLAP +} + +/* Returns 1 if the window parameters are within VID0, 0 otherwise */ +static int within_vid0_limits(u32 xp, u32 yp, u32 xl, u32 yl) +{ + u32 vid0_xp = 0, vid0_yp = 0, vid0_xl = 0, vid0_yl = 0; + + if (!dm->vid0) + return (1); + get_win_position(dm->vid0, &vid0_xp, &vid0_yp, &vid0_xl, &vid0_yl); + if ((xp >= vid0_xp) && (yp >= vid0_yp) && + (xp + xl <= vid0_xp + vid0_xl) && (yp + yl <= vid0_yp + vid0_yl)) + return (1); + return (0); +} + +/* VID0 must be large enough to hold all other windows */ +static int check_new_vid0_size(u32 xp0, u32 yp0, u32 xl0, u32 yl0) +{ + u32 _xp = 0, _yp = 0, _xl = 0, _yl = 0; +#define WITHIN_LIMITS \ + ((_xp >= xp0) && (_yp >= yp0) && \ + (_xp + _xl <= xp0 + xl0) && (_yp + _yl <= yp0 + yl0)) + + if (dm->osd0) { + get_win_position(dm->osd0, &_xp, &_yp, &_xl, &_yl); + if (!WITHIN_LIMITS) + return (-EINVAL); + } + if (dm->osd1) { + get_win_position(dm->osd1, &_xp, &_yp, &_xl, &_yl); + if (!WITHIN_LIMITS) + return (-EINVAL); + } + if (dm->vid1) { + get_win_position(dm->vid1, &_xp, &_yp, &_xl, &_yl); + if (!WITHIN_LIMITS) + return (-EINVAL); + } + return (0); + +#undef WITHIN_LIMITS +} + +/** + * davincifb_check_var - Validates a var passed in. + * @var: frame buffer variable screen structure + * @info: frame buffer structure that represents a single frame buffer + * + * Checks to see if the hardware supports the state requested by + * var passed in. This function does not alter the hardware state!!! + * This means the data stored in struct fb_info and struct xxx_par do + * not change. This includes the var inside of struct fb_info. + * Do NOT change these. This function can be called on its own if we + * intent to only test a mode and not actually set it. + * If the var passed in is slightly off by what the hardware can support + * then we alter the var PASSED in to what we can do. + * + * Returns negative errno on error, or zero on success. + */ +static int davincifb_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + const struct dm_win_info *w = (const struct dm_win_info *)info->par; + struct fb_var_screeninfo v; + +/* Rules: + * 1) Vid1, OSD0, OSD1 and Cursor must be fully contained inside of Vid0. + * 2) Vid0 and Vid1 are both set to accept YUV 4:2:2 (for now). + * 3) OSD window data is always packed into 32-bit words and left justified. + * 4) Each horizontal line of window data must be a multiple of 32 bytes. + * 32 bytes = 32 bytes / 2 bytes per pixel = 16 pixels. + * This implies that 'xres' must be a multiple of 32 bytes. + * 5) The offset registers hold the distance between the start of one line and + * the start of the next. This offset value must be a multiple of 32 bytes. + * This implies that 'xres_virtual' is also a multiple of 32 bytes. Note + * that 'xoffset' needn't be a multiple of 32 bytes. + * 6) OSD0 is set to accept RGB565. + * dispc_reg_merge(OSD_OSDWIN0ND, OSD_OSDWIN0ND_RGB0E, OSD_OSDWIN0ND_RGB0E) + * 7) OSD1 is set to be the attribute window. + * 8) Vid1 startX = Vid0 startX + N * 16 pixels (32 bytes) + * 9) Vid1 width = (16*N - 8) pixels + * 10) When one of the OSD windows is in RGB565, it cannot overlap with Vid1. + * 11) Vid1 start X position must be offset a multiple of 16 pixels from the + * left edge of Vid0. + */ + + memcpy(&v, var, sizeof(v)); + return (0); + + /* do board-specific checks on the var */ + if (davincifb_venc_check_mode(w, &v)) + return (-EINVAL); + + if (v.xres_virtual < v.xres || v.yres_virtual < v.yres) + return (-EINVAL); + if (v.xoffset > v.xres_virtual - v.xres) + return (-EINVAL); + if (v.yoffset > v.yres_virtual - v.yres) + return (-EINVAL); + if ((v.xres * v.bits_per_pixel / 8) % 32 || (v.xres_virtual * v.bits_per_pixel / 8) % 32) /* Rules 4, 5 */ + return (-EINVAL); + if (v.xres_virtual * v.yres_virtual * v.bits_per_pixel / 8 > w->fb_size) + return (-EINVAL); + + if (!is_win(info->fix.id, VID0)) { + /* Rule 1 */ + if (!within_vid0_limits(x_pos(w), y_pos(w), v.xres, v.yres)) + return (-EINVAL); + } + if (is_win(info->fix.id, OSD0)) { + /* Rule 10 */ + if (window_overlap(w->dm->vid1, + x_pos(w), y_pos(w), v.xres, v.yres)) + return (-EINVAL); + /* Rule 5 */ + v.bits_per_pixel = 16; + v.red.offset = 11; + v.green.offset = 5; + v.blue.offset = 0; + v.red.length = 5; + v.green.length = 6; + v.blue.length = 5; + v.transp.offset = v.transp.length = 0; + v.red.msb_right = v.green.msb_right = v.blue.msb_right + = v.transp.msb_right = 0; + v.nonstd = 0; + v.accel_flags = 0; + } else if (is_win(info->fix.id, OSD1)) { + v.bits_per_pixel = 4; + } else if (is_win(info->fix.id, VID0)) { + if (check_new_vid0_size(x_pos(w), y_pos(w), v.xres, v.yres)) + return (-EINVAL); + v.bits_per_pixel = 16; + } else if (is_win(info->fix.id, VID1)) { + /* Rule 11 */ + if ((x_pos(w->dm->vid0) - x_pos(w)) % 16) + return (-EINVAL); + /* Video1 may be in YUV or RGB888 format */ + if ((v.bits_per_pixel != 16) && (v.bits_per_pixel != 32)) + return (-EINVAL); + } else + return (-EINVAL); + + memcpy(var, &v, sizeof(v)); + return (0); +} + +/* Interlaced = Frame mode, Non-interlaced = Field mode */ +static void set_interlaced(char *id, unsigned int on) +{ + on = (on == 0) ? 0 : ~0; + + if (is_win(id, VID0)) + dispc_reg_merge(OSD_VIDWINMD, on, OSD_VIDWINMD_VFF0); + else if (is_win(id, VID1)) + dispc_reg_merge(OSD_VIDWINMD, on, OSD_VIDWINMD_VFF1); + else if (is_win(id, OSD0)) + dispc_reg_merge(OSD_OSDWIN0MD, on, OSD_OSDWIN0MD_OFF0); + else if (is_win(id, OSD1)) + dispc_reg_merge(OSD_OSDWIN1MD, on, OSD_OSDWIN1MD_OFF1); +} + +/* For zooming, we just have to set the start of framebuffer, the zoom factors + * and the display size. The hardware will then read only + * (display size / zoom factor) area of the framebuffer and zoom and + * display it. In the following function, we assume that the start of + * framebuffer and the display size parameters are set already. + */ +static void set_zoom(int WinID, int h_factor, int v_factor) +{ + switch (WinID) { + case 0: //VID0 + dispc_reg_merge(OSD_VIDWINMD, + h_factor << OSD_VIDWINMD_VHZ0_SHIFT, + OSD_VIDWINMD_VHZ0); + dispc_reg_merge(OSD_VIDWINMD, + v_factor << OSD_VIDWINMD_VVZ0_SHIFT, + OSD_VIDWINMD_VVZ0); + break; + case 1: //VID1 + dispc_reg_merge(OSD_VIDWINMD, + h_factor << OSD_VIDWINMD_VHZ1_SHIFT, + OSD_VIDWINMD_VHZ1); + dispc_reg_merge(OSD_VIDWINMD, + v_factor << OSD_VIDWINMD_VVZ1_SHIFT, + OSD_VIDWINMD_VVZ1); + break; + case 2: //OSD0 + dispc_reg_merge(OSD_OSDWIN0MD, + h_factor << OSD_OSDWIN0MD_OHZ0_SHIFT, + OSD_OSDWIN0MD_OHZ0); + dispc_reg_merge(OSD_OSDWIN0MD, + v_factor << OSD_OSDWIN0MD_OVZ0_SHIFT, + OSD_OSDWIN0MD_OVZ0); + break; + case 3: + dispc_reg_merge(OSD_OSDWIN1MD, + h_factor << OSD_OSDWIN1MD_OHZ1_SHIFT, + OSD_OSDWIN1MD_OHZ1); + dispc_reg_merge(OSD_OSDWIN1MD, + v_factor << OSD_OSDWIN1MD_OVZ1_SHIFT, + OSD_OSDWIN1MD_OVZ1); + break; + } +} + +/* Chooses the ROM CLUT for now. Can be extended later. */ +static void set_bg_color(u8 clut, u8 color_offset) +{ + clut = 0; /* 0 = ROM, 1 = RAM */ + + dispc_reg_merge(OSD_MODE, OSD_MODE_BCLUT & clut, OSD_MODE_BCLUT); + dispc_reg_merge(OSD_MODE, color_offset << OSD_MODE_CABG_SHIFT, + OSD_MODE_CABG); +} + +static void set_sdram_params(char *id, u32 addr, u32 line_length) +{ + /* The parameters to be written to the registers should be in + * multiple of 32 bytes + */ + addr = addr; /* div by 32 */ + line_length = line_length / 32; + + if (is_win(id, VID0)) { + dispc_reg_out(OSD_VIDWIN0ADR, addr); + dispc_reg_out(OSD_VIDWIN0OFST, line_length); + } else if (is_win(id, VID1)) { + dispc_reg_out(OSD_VIDWIN1ADR, addr); + dispc_reg_out(OSD_VIDWIN1OFST, line_length); + } else if (is_win(id, OSD0)) { + dispc_reg_out(OSD_OSDWIN0ADR, addr); + dispc_reg_out(OSD_OSDWIN0OFST, line_length); + } else if (is_win(id, OSD1)) { + dispc_reg_out(OSD_OSDWIN1ADR, addr); + dispc_reg_out(OSD_OSDWIN1OFST, line_length); + } +} + +static void set_win_enable(char *id, unsigned int on) +{ + on = (on == 0) ? 0 : ~0; + + if (is_win(id, VID0)) + /* Turning off VID0 use due to field inversion issue */ + dispc_reg_merge(OSD_VIDWINMD, 0, OSD_VIDWINMD_ACT0); + else if (is_win(id, VID1)) + dispc_reg_merge(OSD_VIDWINMD, on, OSD_VIDWINMD_ACT1); + else if (is_win(id, OSD0)) + dispc_reg_merge(OSD_OSDWIN0MD, on, OSD_OSDWIN0MD_OACT0); + else if (is_win(id, OSD1)) { + /* The OACT1 bit is applicable only if OSD1 is not used as + * the attribute window + */ + if (!(dispc_reg_in(OSD_OSDWIN1MD) & OSD_OSDWIN1MD_OASW)) + dispc_reg_merge(OSD_OSDWIN1MD, on, OSD_OSDWIN1MD_OACT1); + } +} + +static void set_win_mode(char *id) +{ + if (is_win(id, VID0)) ; + else if (is_win(id, VID1)) { + if (dm->vid1->info.var.bits_per_pixel == 32) + dispc_reg_merge(OSD_MISCCT, ~0, + OSD_MISCCT_RGBWIN | OSD_MISCCT_RGBEN); + } else if (is_win(id, OSD0)) + /* Set RGB565 mode */ + dispc_reg_merge(OSD_OSDWIN0MD, OSD_OSDWIN0MD_RGB0E, + OSD_OSDWIN0MD_RGB0E); + else if (is_win(id, OSD1)) { + /* Set as attribute window */ + dispc_reg_merge(OSD_OSDWIN1MD, OSD_OSDWIN1MD_OASW, + OSD_OSDWIN1MD_OASW); + } + +} + +/** + * davincifb_set_par - Optional function. Alters the hardware state. + * @info: frame buffer structure that represents a single frame buffer + * + * Using the fb_var_screeninfo in fb_info we set the resolution of the + * this particular framebuffer. This function alters the par AND the + * fb_fix_screeninfo stored in fb_info. It doesn't not alter var in + * fb_info since we are using that data. This means we depend on the + * data in var inside fb_info to be supported by the hardware. + * davincifb_check_var is always called before dmfb_set_par to ensure this. + * Again if you can't can't the resolution you don't need this function. + * + */ +static int davincifb_set_par(struct fb_info *info) +{ + struct dm_win_info *w = (struct dm_win_info *)info->par; + struct fb_var_screeninfo *v = &info->var; + u32 start = 0, offset = 0; + + info->fix.line_length = v->xres_virtual * v->bits_per_pixel / 8; + + offset = v->yoffset * info->fix.line_length + + v->xoffset * v->bits_per_pixel / 8; + start = (u32) w->fb_base_phys + offset; + set_sdram_params(info->fix.id, start, info->fix.line_length); + + set_interlaced(info->fix.id, 1); + set_win_position(info->fix.id, + x_pos(w), y_pos(w), v->xres, v->yres / 2); + set_win_mode(info->fix.id); + set_win_enable(info->fix.id, 1); + + return (0); +} + +/** + * davincifb_ioctl - handler for private ioctls. + */ +static int davincifb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct dm_win_info *w = (struct dm_win_info *)info->par; + void __user *argp = (void __user *)arg; + struct fb_fillrect rect; + struct zoom_params zoom; + long std = 0; + + switch (cmd) { + case FBIO_WAITFORVSYNC: + /* This ioctl accepts an integer argument to specify a + * display. We only support one display, so we will + * simply ignore the argument. + */ + return (davincifb_wait_for_vsync(w)); + break; + case FBIO_SETATTRIBUTE: + if (copy_from_user(&rect, argp, sizeof(rect))) + return -EFAULT; + return (davincifb_set_attr_blend(&rect)); + break; + case FBIO_SETPOSX: + if (arg >= 0 && arg <= DISP_XRES) { + w->x = arg; + davincifb_check_var(&w->info.var, &w->info); + davincifb_set_par(&w->info); + return 0; + } else + return -EINVAL; + break; + case FBIO_SETPOSY: + if (arg >= 0 && arg <= DISP_YRES) { + w->y = arg; + davincifb_check_var(&w->info.var, &w->info); + davincifb_set_par(&w->info); + return 0; + } else + return -EINVAL; + break; + case FBIO_SETZOOM: + if (copy_from_user(&zoom, argp, sizeof(zoom))) + return -EFAULT; + if ((zoom.zoom_h == 2) || (zoom.zoom_h == 0) + || (zoom.zoom_h == 1) || (zoom.zoom_v == 2) + || (zoom.zoom_v == 0) || (zoom.zoom_v == 1)) { + set_zoom(zoom.window_id, zoom.zoom_h, zoom.zoom_v); + return 0; + } else { + return -EINVAL; + } + break; + case FBIO_GETSTD: + std = ((dmparams.output << 16) | (dmparams.format)); //(NTSC <<16) | (COPOSITE); + if (copy_to_user(argp, &std, sizeof(u_int32_t))) + return -EFAULT; + return 0; + break; + } + return (-EINVAL); +} + +/** + * davincifb_setcolreg - Optional function. Sets a color register. + * @regno: Which register in the CLUT we are programming + * @red: The red value which can be up to 16 bits wide + * @green: The green value which can be up to 16 bits wide + * @blue: The blue value which can be up to 16 bits wide. + * @transp: If supported the alpha value which can be up to 16 bits wide. + * @info: frame buffer info structure + * + * Set a single color register. The values supplied have a 16 bit + * magnitude which needs to be scaled in this function for the hardware. + * Things to take into consideration are how many color registers, if + * any, are supported with the current color visual. With truecolor mode + * no color palettes are supported. Here a psuedo palette is created + * which we store the value in pseudo_palette in struct fb_info. For + * pseudocolor mode we have a limited color palette. To deal with this + * we can program what color is displayed for a particular pixel value. + * DirectColor is similar in that we can program each color field. If + * we have a static colormap we don't need to implement this function. + * + * Returns negative errno on error, or zero on success. + */ +static int davincifb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + /* only pseudo-palette (16 bpp) allowed */ + if (regno >= 16) /* maximum number of palette entries */ + return (1); + + if (info->var.grayscale) { + /* grayscale = 0.30*R + 0.59*G + 0.11*B */ + red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; + } + + /* Truecolor has hardware-independent 16-entry pseudo-palette */ + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 v; + + if (regno >= 16) + return (1); + + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + + switch (info->var.bits_per_pixel) { + case 16: + ((u16 *) (info->pseudo_palette))[regno] = v; + break; + default: + return (1); + } + return (0); + } + return (0); +} + +/** + * davincifb_pan_display - NOT a required function. Pans the display. + * @var: frame buffer variable screen structure + * @info: frame buffer structure that represents a single frame buffer + * + * Pan (or wrap, depending on the `vmode' field) the display using the + * `xoffset' and `yoffset' fields of the `var' structure. + * If the values don't fit, return -EINVAL. + * + * Returns negative errno on error, or zero on success. + */ +static int davincifb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + struct dm_win_info *w = (struct dm_win_info *)info->par; + u32 start = 0, offset = 0; + + if (var->xoffset > var->xres_virtual - var->xres) + return (-EINVAL); + if (var->yoffset > var->yres_virtual - var->yres) + return (-EINVAL); + if ((var->xres_virtual * var->bits_per_pixel / 8) % 32) + return (-EINVAL); + + offset = var->yoffset * info->fix.line_length + + var->xoffset * var->bits_per_pixel / 8; + start = (u32) w->fb_base_phys + offset; + + if ((dispc_reg_in(VENC_VSTAT) & 0x00000010)==0x10) + set_sdram_params(info->fix.id, start, info->fix.line_length); + else + w->sdram_address = start; + + return (0); +} + +/** + * davincifb_blank - NOT a required function. Blanks the display. + * @blank_mode: the blank mode we want. + * @info: frame buffer structure that represents a single frame buffer + * + * Blank the screen if blank_mode != 0, else unblank. Return 0 if + * blanking succeeded, != 0 if un-/blanking failed due to e.g. a + * video mode which doesn't support it. Implements VESA suspend + * and powerdown modes on hardware that supports disabling hsync/vsync: + * blank_mode == 2: suspend vsync + * blank_mode == 3: suspend hsync + * blank_mode == 4: powerdown + * + * Returns negative errno on error, or zero on success. + * + */ +static int davincifb_blank(int blank_mode, struct fb_info *info) +{ + return 0; +} + +static int parse_win_params(char *wp, + int *xres, int *yres, int *xpos, int *ypos) +{ + char *s; + + if ((s = strsep(&wp, "x")) == NULL) + return -EINVAL; + *xres = simple_strtoul(s, NULL, 0); + + if ((s = strsep(&wp, "@")) == NULL) + return -EINVAL; + *yres = simple_strtoul(s, NULL, 0); + + if ((s = strsep(&wp, ",")) == NULL) + return -EINVAL; + *xpos = simple_strtoul(s, NULL, 0); + + if ((s = strsep(&wp, ":")) == NULL) + return -EINVAL; + *ypos = simple_strtoul(s, NULL, 0); + + return 0; +} + +/* + * Pass boot-time options by adding the following string to the boot params: + * video=davincifb:[option[:option]] + * Valid options: + * output=[lcd|ntsc|pal] + * format=[composite|s-video|component|rgb] + * vid0=[off|MxN@X,Y] + * vid1=[off|MxN@X,Y] + * osd0=[off|MxN@X,Y] + * osd1=[off|MxN@X,Y] + * MxN specify the window resolution (displayed size) + * X,Y specify the window position + * M, N, X, Y are integers + * M, X should be multiples of 16 + */ + +#ifndef MODULE +int __init davincifb_setup(char *options) +{ + char *this_opt; + u32 xres, yres, xpos, ypos; + int format_yres = 480; + + pr_debug("davincifb: Options \"%s\"\n", options); + + if (!options || !*options) + return 0; + + while ((this_opt = strsep(&options, ":")) != NULL) { + + if (!*this_opt) + continue; + + if (!strncmp(this_opt, "output=", 7)) { + if (!strncmp(this_opt + 7, "lcd", 3)) { + dmparams.output = LCD; + dmparams.format = 0; + } else if (!strncmp(this_opt + 7, "ntsc", 4)) + dmparams.output = NTSC; + else if (!strncmp(this_opt + 7, "pal", 3)) + dmparams.output = PAL; + } else if (!strncmp(this_opt, "format=", 7)) { + if (dmparams.output == LCD) + continue; + if (!strncmp(this_opt + 7, "composite", 9)) + dmparams.format = COMPOSITE; + else if (!strncmp(this_opt + 7, "s-video", 7)) + dmparams.format = SVIDEO; + else if (!strncmp(this_opt + 7, "component", 9)) + dmparams.format = COMPONENT; + else if (!strncmp(this_opt + 7, "rgb", 3)) + dmparams.format = RGB; + } else if (!strncmp(this_opt, "vid0=", 5)) { + if (!strncmp(this_opt + 5, "off", 3)) + dmparams.windows &= ~(1 << VID0); + else if (!parse_win_params(this_opt + 5, + &xres, &yres, &xpos, + &ypos)) { + dmparams.vid0_xres = xres; + dmparams.vid0_yres = yres; + dmparams.vid0_xpos = xpos; + dmparams.vid0_ypos = ypos; + } + } else if (!strncmp(this_opt, "vid1=", 5)) { + if (!strncmp(this_opt + 5, "off", 3)) + dmparams.windows &= ~(1 << VID1); + else if (!parse_win_params(this_opt + 5, + &xres, &yres, &xpos, + &ypos)) { + dmparams.vid1_xres = xres; + dmparams.vid1_yres = yres; + dmparams.vid1_xpos = xpos; + dmparams.vid1_ypos = ypos; + } + } else if (!strncmp(this_opt, "osd0=", 5)) { + if (!strncmp(this_opt + 5, "off", 3)) + dmparams.windows &= ~(1 << OSD0); + else if (!parse_win_params(this_opt + 5, + &xres, &yres, &xpos, + &ypos)) { + dmparams.osd0_xres = xres; + dmparams.osd0_yres = yres; + dmparams.osd0_xpos = xpos; + dmparams.osd0_ypos = ypos; + } + } else if (!strncmp(this_opt, "osd1=", 5)) { + if (!strncmp(this_opt + 5, "off", 3)) + dmparams.windows &= ~(1 << OSD1); + else if (!parse_win_params(this_opt + 5, + &xres, &yres, &xpos, + &ypos)) { + dmparams.osd1_xres = xres; + dmparams.osd1_yres = yres; + dmparams.osd1_xpos = xpos; + dmparams.osd1_ypos = ypos; + } + } + } + printk(KERN_INFO "DaVinci: " + "Output on %s%s, Enabled windows: %s %s %s %s\n", + (dmparams.output == LCD) ? "LCD" : + (dmparams.output == NTSC) ? "NTSC" : + (dmparams.output == PAL) ? "PAL" : "unknown device!", + (dmparams.format == 0) ? "" : + (dmparams.format == COMPOSITE) ? " in COMPOSITE format" : + (dmparams.format == SVIDEO) ? " in SVIDEO format" : + (dmparams.format == COMPONENT) ? " in COMPONENT format" : + (dmparams.format == RGB) ? " in RGB format" : "", + (dmparams.windows & (1 << VID0)) ? "Video0" : "", + (dmparams.windows & (1 << VID1)) ? "Video1" : "", + (dmparams.windows & (1 << OSD0)) ? "OSD0" : "", + (dmparams.windows & (1 << OSD1)) ? "OSD1" : ""); + if (dmparams.output == NTSC) { + format_yres = 480; + } else if (dmparams.output == PAL) { + format_yres = 576; + } else { + printk(KERN_INFO + "DaVinci:invalid format..defaulting width to 480\n"); + } + dmparams.osd0_yres = osd0_default_var.yres = format_yres; + dmparams.osd1_yres = osd1_default_var.yres = format_yres; + dmparams.vid0_yres = vid0_default_var.yres = format_yres; + dmparams.vid1_yres = vid1_default_var.yres = format_yres; + + osd0_default_var.yres_virtual = format_yres * DOUBLE_BUF; + osd1_default_var.yres_virtual = format_yres * DOUBLE_BUF; + vid0_default_var.yres_virtual = format_yres * TRIPLE_BUF; + vid1_default_var.yres_virtual = format_yres * TRIPLE_BUF; + + if (dmparams.windows & (1 << VID0)) + printk(KERN_INFO "Setting Video0 size %dx%d, " + "position (%d,%d)\n", + dmparams.vid0_xres, dmparams.vid0_yres, + dmparams.vid0_xpos, dmparams.vid0_ypos); + if (dmparams.windows & (1 << VID1)) + printk(KERN_INFO "Setting Video1 size %dx%d, " + "position (%d,%d)\n", + dmparams.vid1_xres, dmparams.vid1_yres, + dmparams.vid1_xpos, dmparams.vid1_ypos); + if (dmparams.windows & (1 << OSD0)) + printk(KERN_INFO "Setting OSD0 size %dx%d, " + "position (%d,%d)\n", + dmparams.osd0_xres, dmparams.osd0_yres, + dmparams.osd0_xpos, dmparams.osd0_ypos); + if (dmparams.windows & (1 << OSD1)) + printk(KERN_INFO "Setting OSD1 size %dx%d, " + "position (%d,%d)\n", + dmparams.osd1_xres, dmparams.osd1_yres, + dmparams.osd1_xpos, dmparams.osd1_ypos); + return (0); +} +#endif + +static int mem_release(struct dm_win_info *w) +{ + if (!w->alloc_fb_mem) { + iounmap((void *)w->fb_base); + release_mem_region(w->fb_base_phys, w->fb_size); + } else + dma_free_coherent(NULL, w->fb_size, (void *)w->fb_base, + w->fb_base_phys); + kfree(w); + return (0); +} + +static int mem_alloc(struct dm_win_info **win, dma_addr_t fb_base_phys, + unsigned long fb_size, char *fbname) +{ + struct dm_win_info *w; + struct device *dev = dm->dev; + + w = kmalloc(sizeof(struct dm_win_info), GFP_KERNEL); + if (!w) { + dev_err(dev, "%s: could not allocate memory\n", fbname); + return (-ENOMEM); + } + memset(w, 0, sizeof(struct dm_win_info)); + + w->fb_base_phys = fb_base_phys; + w->fb_size = fb_size; + + /* A null base address indicates that the framebuffer memory should be + * dynamically allocated. + */ + if (!w->fb_base_phys) + w->alloc_fb_mem = 1; + + if (!w->alloc_fb_mem) { + if (!request_mem_region(w->fb_base_phys, w->fb_size, fbname)) { + dev_err(dev, "%s: cannot reserve FB region\n", fbname); + goto free_par; + } + w->fb_base = + (unsigned long)ioremap(w->fb_base_phys, w->fb_size); + if (!w->fb_base) { + dev_err(dev, "%s: cannot map framebuffer\n", fbname); + goto release_fb; + } + } else { + /* allocate coherent memory for the framebuffer */ + w->fb_base = (unsigned long)dma_alloc_coherent(dev, + w->fb_size, + &w->fb_base_phys, + GFP_KERNEL | + GFP_DMA); + if (!w->fb_base) { + dev_err(dev, "%s: cannot allocate framebuffer\n", + fbname); + goto free_par; + } + + dev_dbg(dev, "Framebuffer allocated at 0x%x " + "mapped to 0x%x, size %dk\n", + (unsigned)w->fb_base_phys, (unsigned)w->fb_base, + (unsigned)w->fb_size / 1024); + } + + *win = w; + return (0); + + release_fb: + if (!w->alloc_fb_mem) + release_mem_region(w->fb_base_phys, w->fb_size); + free_par: + kfree(w); + return (-ENOMEM); +} + +static struct fb_info *init_fb_info(struct dm_win_info *w, + struct fb_var_screeninfo *var, char *id) +{ + struct fb_info *info = &(w->info); + struct dm_info *dm = w->dm; + + /* initialize the fb_info structure */ + info->flags = FBINFO_DEFAULT; + info->fbops = &davincifb_ops; + info->screen_base = (char *)(w->fb_base); + info->pseudo_palette = w->pseudo_palette; + info->par = w; + + /* Initialize variable screeninfo. + * The variable screeninfo can be directly specified by the user + * via an ioctl. + */ + memcpy(&info->var, var, sizeof(info->var)); + info->var.activate = FB_ACTIVATE_NOW; + + /* Initialize fixed screeninfo. + * The fixed screeninfo cannot be directly specified by the user, but + * it may change to reflect changes to the var info. + */ + strlcpy(info->fix.id, id, sizeof(info->fix.id)); + info->fix.smem_start = w->fb_base_phys; + info->fix.line_length = + (info->var.xres_virtual * info->var.bits_per_pixel) / 8; + info->fix.smem_len = w->fb_size; + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = (info->var.bits_per_pixel <= 8) ? + FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; + info->fix.xpanstep = 0; + info->fix.ypanstep = 1; + info->fix.ywrapstep = 0; + info->fix.type_aux = 0; + info->fix.mmio_start = dm->mmio_base_phys; + info->fix.mmio_len = dm->mmio_size; + info->fix.accel = FB_ACCEL_NONE; + w->sdram_address = 0; + + return info; +} + +static void davincifb_ntsc_composite_config(int on) +{ + if (on) { + /* Reset video encoder module */ + dispc_reg_out(VENC_VMOD, 0); + + /* Enable Composite output and start video encoder */ + dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC)); + + /* Set REC656 Mode */ + dispc_reg_out(VENC_YCCCTL, 0x1); + + /* Enable output mode and NTSC */ + dispc_reg_out(VENC_VMOD, 0x1003); + + /* Enable all DACs */ + dispc_reg_out(VENC_DACTST, 0); + } else { + /* Reset video encoder module */ + dispc_reg_out(VENC_VMOD, 0); + } +} + +static void davincifb_ntsc_svideo_config(int on) +{ + if (on) { + /* Reset video encoder module */ + dispc_reg_out(VENC_VMOD, 0); + + /* Enable Composite output and start video encoder */ + dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC)); + + /* Set REC656 Mode */ + dispc_reg_out(VENC_YCCCTL, 0x1); + + /* Enable output mode and NTSC */ + dispc_reg_out(VENC_VMOD, 0x1003); + + /* Enable S-Video Output; DAC B: S-Video Y, DAC C: S-Video C */ + dispc_reg_out(VENC_DACSEL, 0x210); + + /* Enable all DACs */ + dispc_reg_out(VENC_DACTST, 0); + } else { + /* Reset video encoder module */ + dispc_reg_out(VENC_VMOD, 0); + } +} + +static void davincifb_ntsc_component_config(int on) +{ + if (on) { + /* Reset video encoder module */ + dispc_reg_out(VENC_VMOD, 0); + + /* Enable Composite output and start video encoder */ + dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC)); + + /* Set REC656 Mode */ + dispc_reg_out(VENC_YCCCTL, 0x1); + + /* Enable output mode and NTSC */ + dispc_reg_out(VENC_VMOD, 0x1003); + + /* Enable Component output; DAC A: Y, DAC B: Pb, DAC C: Pr */ + dispc_reg_out(VENC_DACSEL, 0x543); + + /* Enable all DACs */ + dispc_reg_out(VENC_DACTST, 0); + } else { + /* Reset video encoder module */ + dispc_reg_out(VENC_VMOD, 0); + } +} + +static void davincifb_pal_composite_config(int on) +{ + if (on) { + /* Reset video encoder module */ + dispc_reg_out(VENC_VMOD, 0); + + /* Enable Composite output and start video encoder */ + dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC)); + + /* Set REC656 Mode */ + dispc_reg_out(VENC_YCCCTL, 0x1); + + /* Enable output mode and PAL */ + dispc_reg_out(VENC_VMOD, 0x1043); + + /* Enable all DACs */ + dispc_reg_out(VENC_DACTST, 0); + } else { + /* Reset video encoder module */ + dispc_reg_out(VENC_VMOD, 0); + } +} + +static void davincifb_pal_svideo_config(int on) +{ + if (on) { + /* Reset video encoder module */ + dispc_reg_out(VENC_VMOD, 0); + + /* Enable Composite output and start video encoder */ + dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC)); + + /* Set REC656 Mode */ + dispc_reg_out(VENC_YCCCTL, 0x1); + + /* Enable output mode and PAL */ + dispc_reg_out(VENC_VMOD, 0x1043); + + /* Enable S-Video Output; DAC B: S-Video Y, DAC C: S-Video C */ + dispc_reg_out(VENC_DACSEL, 0x210); + + /* Enable all DACs */ + dispc_reg_out(VENC_DACTST, 0); + } else { + /* Reset video encoder module */ + dispc_reg_out(VENC_VMOD, 0); + } +} + +static void davincifb_pal_component_config(int on) +{ + if (on) { + /* Reset video encoder module */ + dispc_reg_out(VENC_VMOD, 0); + + /* Enable Composite output and start video encoder */ + dispc_reg_out(VENC_VMOD, (VENC_VMOD_VIE | VENC_VMOD_VENC)); + + /* Set REC656 Mode */ + dispc_reg_out(VENC_YCCCTL, 0x1); + + /* Enable output mode and PAL */ + dispc_reg_out(VENC_VMOD, 0x1043); + + /* Enable Component output; DAC A: Y, DAC B: Pb, DAC C: Pr */ + dispc_reg_out(VENC_DACSEL, 0x543); + + /* Enable all DACs */ + dispc_reg_out(VENC_DACTST, 0); + } else { + /* Reset video encoder module */ + dispc_reg_out(VENC_VMOD, 0); + } +} + +static inline void fix_default_var(struct dm_win_info *w, + u32 xres, u32 yres, u32 xpos, u32 ypos, + int n_buf) +{ + struct fb_var_screeninfo *v = &w->info.var; + + v->xres = xres; + v->yres = yres; + v->xres_virtual = v->xres; + v->yres_virtual = v->yres * n_buf; + x_pos(w) = xpos; + y_pos(w) = ypos; +} + +/* + * Cleanup + */ +static int davincifb_remove(struct platform_device *pdev) +{ + free_irq(IRQ_VENCINT, &dm); + + /* Cleanup all framebuffers */ + if (dm->osd0) { + unregister_framebuffer(&dm->osd0->info); + mem_release(dm->osd0); + } + if (dm->osd1) { + unregister_framebuffer(&dm->osd1->info); + mem_release(dm->osd1); + } + if (dm->vid0) { + unregister_framebuffer(&dm->vid0->info); + mem_release(dm->vid0); + } + if (dm->vid1) { + unregister_framebuffer(&dm->vid1->info); + mem_release(dm->vid1); + } + + /* Turn OFF the output device */ + dm->output_device_config(0); + + if (dm->mmio_base) + iounmap((void *)dm->mmio_base); + release_mem_region(dm->mmio_base_phys, dm->mmio_size); + + return 0; +} + +/* + * Initialization + */ +static int davincifb_probe(struct platform_device *pdev) +{ + struct fb_info *info; + + if (dmparams.windows == 0) + return 0; /* user disabled all windows through bootargs */ + dm->dev = &pdev->dev; + dm->mmio_base_phys = OSD_REG_BASE; + dm->mmio_size = OSD_REG_SIZE; + + if (!request_mem_region + (dm->mmio_base_phys, dm->mmio_size, MODULE_NAME)) { + dev_err(dm->dev, ": cannot reserve MMIO region\n"); + return (-ENODEV); + } + + /* map the regions */ + dm->mmio_base = + (unsigned long)ioremap(dm->mmio_base_phys, dm->mmio_size); + if (!dm->mmio_base) { + dev_err(dm->dev, ": cannot map MMIO\n"); + goto release_mmio; + } + + /* initialize the vsync wait queue */ + init_waitqueue_head(&dm->vsync_wait); + dm->timeout = HZ / 5; + + if ((dmparams.output == NTSC) && (dmparams.format == COMPOSITE)) + dm->output_device_config = davincifb_ntsc_composite_config; + else if ((dmparams.output == NTSC) && (dmparams.format == SVIDEO)) + dm->output_device_config = davincifb_ntsc_svideo_config; + else if ((dmparams.output == NTSC) && (dmparams.format == COMPONENT)) + dm->output_device_config = davincifb_ntsc_component_config; + else if ((dmparams.output == PAL) && (dmparams.format == COMPOSITE)) + dm->output_device_config = davincifb_pal_composite_config; + else if ((dmparams.output == PAL) && (dmparams.format == SVIDEO)) + dm->output_device_config = davincifb_pal_svideo_config; + else if ((dmparams.output == PAL) && (dmparams.format == COMPONENT)) + dm->output_device_config = davincifb_pal_component_config; + /* Add support for other displays here */ + else { + printk(KERN_WARNING "Unsupported output device!\n"); + dm->output_device_config = NULL; + } + + printk("Setting Up Clocks for DM420 OSD\n"); + + /* Initialize the VPSS Clock Control register */ + dispc_reg_out(VPSS_CLKCTL, 0x18); + + /* Set Base Pixel X and Base Pixel Y */ + dispc_reg_out(OSD_BASEPX, BASEX); + dispc_reg_out(OSD_BASEPY, BASEY); + + /* Reset OSD registers to default. */ + dispc_reg_out(OSD_MODE, 0); + dispc_reg_out(OSD_OSDWIN0MD, 0); + + /* Set blue background color */ + set_bg_color(0, 162); + + /* Field Inversion Workaround */ + dispc_reg_out(OSD_MODE, 0x200); + + /* Setup VID0 framebuffer */ + if (!(dmparams.windows & (1 << VID0))) { + printk(KERN_WARNING "No video/osd windows will be enabled " + "because Video0 is disabled\n"); + return 0; /* background will still be shown */ + } + /* Setup VID0 framebuffer */ + if (!mem_alloc(&dm->vid0, VID0_FB_PHY, VID0_FB_SIZE, VID0_FBNAME)) { + dm->vid0->dm = dm; + fix_default_var(dm->vid0, + dmparams.vid0_xres, dmparams.vid0_yres, + dmparams.vid0_xpos, dmparams.vid0_ypos, + TRIPLE_BUF); + info = init_fb_info(dm->vid0, &vid0_default_var, VID0_FBNAME); + if (davincifb_check_var(&info->var, info)) { + dev_err(dm->dev, ": invalid default video mode\n"); + goto exit; + } + memset((void *)dm->vid0->fb_base, 0x88, dm->vid0->fb_size); + } else + goto exit; + + /* Setup OSD0 framebuffer */ + if ((dmparams.windows & (1 << OSD0)) && + (!mem_alloc(&dm->osd0, OSD0_FB_PHY, OSD0_FB_SIZE, OSD0_FBNAME))) { + dm->osd0->dm = dm; + fix_default_var(dm->osd0, + dmparams.osd0_xres, dmparams.osd0_yres, + dmparams.osd0_xpos, dmparams.osd0_ypos, + DOUBLE_BUF); + info = init_fb_info(dm->osd0, &osd0_default_var, OSD0_FBNAME); + if (davincifb_check_var(&info->var, info)) { + dev_err(dm->dev, ": invalid default video mode\n"); + mem_release(dm->osd0); + } else + memset((void *)dm->osd0->fb_base, 0, dm->osd0->fb_size); + } + + /* Setup OSD1 framebuffer */ + if ((dmparams.windows & (1 << OSD1)) && + (!mem_alloc(&dm->osd1, OSD1_FB_PHY, OSD1_FB_SIZE, OSD1_FBNAME))) { + dm->osd1->dm = dm; + fix_default_var(dm->osd1, + dmparams.osd1_xres, dmparams.osd1_yres, + dmparams.osd1_xpos, dmparams.osd1_ypos, + DOUBLE_BUF); + info = init_fb_info(dm->osd1, &osd1_default_var, OSD1_FBNAME); + if (davincifb_check_var(&info->var, info)) { + dev_err(dm->dev, ": invalid default video mode\n"); + mem_release(dm->osd1); + } else + /* Set blend factor to show OSD windows */ + memset((void *)dm->osd1->fb_base, 0xff, + dm->osd1->fb_size); + } + + /* Setup VID1 framebuffer */ + if ((dmparams.windows & (1 << VID1)) && + (!mem_alloc(&dm->vid1, VID1_FB_PHY, VID1_FB_SIZE, VID1_FBNAME))) { + dm->vid1->dm = dm; + fix_default_var(dm->vid1, + dmparams.vid1_xres, dmparams.vid1_yres, + dmparams.vid1_xpos, dmparams.vid1_ypos, + TRIPLE_BUF); + info = init_fb_info(dm->vid1, &vid1_default_var, VID1_FBNAME); + if (davincifb_check_var(&info->var, info)) { + dev_err(dm->dev, + VID1_FBNAME ": invalid default video mode\n"); + mem_release(dm->vid1); + } else + memset((void *)dm->vid1->fb_base, 0x88, + dm->vid1->fb_size); + } + + /* Register OSD0 framebuffer */ + if (dm->osd0) { + info = &dm->osd0->info; + if (register_framebuffer(info) < 0) { + dev_err(dm->dev, OSD0_FBNAME + "Unable to register OSD0 framebuffer\n"); + mem_release(dm->osd0); + } else { + printk(KERN_INFO "fb%d: %s frame buffer device\n", + info->node, info->fix.id); + davincifb_set_par(info); + } + } + + /* Register VID0 framebuffer */ + info = &dm->vid0->info; + if (register_framebuffer(info) < 0) { + dev_err(dm->dev, + VID0_FBNAME "Unable to register VID0 framebuffer\n"); + goto exit; + } else { + printk(KERN_INFO "fb%d: %s frame buffer device\n", + info->node, info->fix.id); + davincifb_set_par(info); + } + + /* Register OSD1 framebuffer */ + if (dm->osd1) { + info = &dm->osd1->info; + if (register_framebuffer(info) < 0) { + dev_err(dm->dev, OSD1_FBNAME + "Unable to register OSD1 framebuffer\n"); + mem_release(dm->osd1); + } else { + printk(KERN_INFO "fb%d: %s frame buffer device\n", + info->node, info->fix.id); + davincifb_set_par(info); + } + } + + /* Register VID1 framebuffer */ + if (dm->vid1) { + info = &dm->vid1->info; + if (register_framebuffer(info) < 0) { + mem_release(dm->vid1); + dev_err(dm->dev, VID1_FBNAME + "Unable to register VID1 framebuffer\n"); + mem_release(dm->vid1); + } else { + printk(KERN_INFO "fb%d: %s frame buffer device\n", + info->node, info->fix.id); + davincifb_set_par(info); + } + } + + /* install our interrupt service routine */ + if (request_irq(IRQ_VENCINT, davincifb_isr, IRQF_SHARED, MODULE_NAME, + dm)) { + dev_err(dm->dev, MODULE_NAME + ": could not install interrupt service routine\n"); + goto exit; + } + + /* Turn ON the output device */ + dm->output_device_config(1); + + return (0); + + exit: + davincifb_remove(pdev); + iounmap((void *)dm->mmio_base); + release_mmio: + release_mem_region(dm->mmio_base_phys, dm->mmio_size); + return (-ENODEV); +} + +/* ------------------------------------------------------------------------- */ + + /* + * Frame buffer operations + */ +static struct fb_ops davincifb_ops = { + .owner = THIS_MODULE, + .fb_check_var = davincifb_check_var, + .fb_set_par = davincifb_set_par, + .fb_setcolreg = davincifb_setcolreg, + .fb_blank = davincifb_blank, + .fb_pan_display = davincifb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_rotate = NULL, + .fb_sync = NULL, + .fb_ioctl = davincifb_ioctl, +}; + +static struct platform_driver davincifb_driver = { + .probe = davincifb_probe, + .remove = davincifb_remove, + .driver = { + .name = MODULE_NAME, + .owner = THIS_MODULE, + }, +}; + +/* Register both the driver and the device */ +int __init davincifb_init(void) +{ +#ifndef MODULE + /* boot-line options */ + /* handle options for "dm64xxfb" for backwards compatability */ + char *option; + char *names[] = { "davincifb", "dm64xxfb" }; + int i, num_names = 2, done = 0; + + for (i = 0; i < num_names && !done; i++) { + if (fb_get_options(names[i], &option)) { + printk(MODULE_NAME + ": Disabled on command-line.\n"); + return -ENODEV; + } else if (option) { + davincifb_setup(option); + done = 1; + } + } +#endif + + /* Register the driver with LDM */ + if (platform_driver_register(&davincifb_driver)) { + pr_debug("failed to register omapfb driver\n"); + return -ENODEV; + } + + return 0; +} + +static void __exit davincifb_cleanup(void) +{ + platform_driver_unregister(&davincifb_driver); +} + +module_init(davincifb_init); +module_exit(davincifb_cleanup); + +MODULE_DESCRIPTION("Framebuffer driver for TI DaVinci"); +MODULE_AUTHOR("Texas Instruments"); +MODULE_LICENSE("GPL"); diff --git a/include/video/davincifb.h b/include/video/davincifb.h new file mode 100644 index 000000000000..96b5c20c349c --- /dev/null +++ b/include/video/davincifb.h @@ -0,0 +1,442 @@ +/* + * include/video/davincifb.h + * + * Framebuffer driver for Texas Instruments DM644x display controller. + * + * Copyright (C) 2006 Texas Instruments, Inc. + * Rishi Bhattacharya <support@ti.com> + * + * 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. + */ +#ifndef _DAVINCIFB_H_ +#define _DAVINCIFB_H_ + +#include <mach/io.h> + +/* Base registers */ +#define VPBE_REG_BASE 0x01c72780 +#define VENC_REG_BASE 0x01c72400 +#define OSD_REG_BASE 0x01c72600 +#define OSD_REG_SIZE 0x00000180 + +/* VPBE Global Registers */ +#define VPBE_PID (VPBE_BASE + 0x0) +#define VPBE_PCR (VPBE_BASE + 0x4) + +/* VPSS Clock Control Register */ +#define VPSS_CLKCTL 0x01c40044 + +/* VPBE Video Encoder / Digital LCD Subsystem Registers (VENC) */ +#define VENC_VMOD (VENC_REG_BASE + 0x00) +#define VENC_VIDCTL (VENC_REG_BASE + 0x04) +#define VENC_VDPRO (VENC_REG_BASE + 0x08) +#define VENC_SYNCCTL (VENC_REG_BASE + 0x0C) +#define VENC_HSPLS (VENC_REG_BASE + 0x10) +#define VENC_VSPLS (VENC_REG_BASE + 0x14) +#define VENC_HINT (VENC_REG_BASE + 0x18) +#define VENC_HSTART (VENC_REG_BASE + 0x1C) +#define VENC_HVALID (VENC_REG_BASE + 0x20) +#define VENC_VINT (VENC_REG_BASE + 0x24) +#define VENC_VSTART (VENC_REG_BASE + 0x28) +#define VENC_VVALID (VENC_REG_BASE + 0x2C) +#define VENC_HSDLY (VENC_REG_BASE + 0x30) +#define VENC_VSDLY (VENC_REG_BASE + 0x34) +#define VENC_YCCCTL (VENC_REG_BASE + 0x38) +#define VENC_RGBCTL (VENC_REG_BASE + 0x3C) +#define VENC_RGBCLP (VENC_REG_BASE + 0x40) +#define VENC_LINECTL (VENC_REG_BASE + 0x44) +#define VENC_CULLLINE (VENC_REG_BASE + 0x48) +#define VENC_LCDOUT (VENC_REG_BASE + 0x4C) +#define VENC_BRTS (VENC_REG_BASE + 0x50) +#define VENC_BRTW (VENC_REG_BASE + 0x54) +#define VENC_ACCTL (VENC_REG_BASE + 0x58) +#define VENC_PWMP (VENC_REG_BASE + 0x5C) +#define VENC_PWMW (VENC_REG_BASE + 0x60) +#define VENC_DCLKCTL (VENC_REG_BASE + 0x64) +#define VENC_DCLKPTN0 (VENC_REG_BASE + 0x68) +#define VENC_DCLKPTN1 (VENC_REG_BASE + 0x6C) +#define VENC_DCLKPTN2 (VENC_REG_BASE + 0x70) +#define VENC_DCLKPTN3 (VENC_REG_BASE + 0x74) +#define VENC_DCLKPTN0A (VENC_REG_BASE + 0x78) +#define VENC_DCLKPTN1A (VENC_REG_BASE + 0x7C) +#define VENC_DCLKPTN2A (VENC_REG_BASE + 0x80) +#define VENC_DCLKPTN3A (VENC_REG_BASE + 0x84) +#define VENC_DCLKHS (VENC_REG_BASE + 0x88) +#define VENC_DCLKHSA (VENC_REG_BASE + 0x8C) +#define VENC_DCLKHR (VENC_REG_BASE + 0x90) +#define VENC_DCLKVS (VENC_REG_BASE + 0x94) +#define VENC_DCLKVR (VENC_REG_BASE + 0x98) +#define VENC_CAPCTL (VENC_REG_BASE + 0x9C) +#define VENC_CAPDO (VENC_REG_BASE + 0xA0) +#define VENC_CAPDE (VENC_REG_BASE + 0xA4) +#define VENC_ATR0 (VENC_REG_BASE + 0xA8) +#define VENC_ATR1 (VENC_REG_BASE + 0xAC) +#define VENC_ATR2 (VENC_REG_BASE + 0xB0) +#define VENC_EPSON_LCDCTL (VENC_REG_BASE + 0xB4) +#define VENC_CASIO_LCDCTL (VENC_REG_BASE + 0xB4) +#define VENC_UDISP_LCDCT (VENC_REG_BASE + 0xB4) +#define VENC_STN_LCDCT (VENC_REG_BASE + 0xB4) +#define VENC_VSTAT (VENC_REG_BASE + 0xB8) +#define VENC_RAMADR (VENC_REG_BASE + 0xBC) +#define VENC_RAMPORT (VENC_REG_BASE + 0xC0) +#define VENC_DACTST (VENC_REG_BASE + 0xC4) +#define VENC_YCOLVL (VENC_REG_BASE + 0xC8) +#define VENC_SCPROG (VENC_REG_BASE + 0xCC) +#define VENC_CVBS (VENC_REG_BASE + 0xDC) +#define VENC_CMPNT (VENC_REG_BASE + 0xE0) +#define VENC_ETMG0 (VENC_REG_BASE + 0xE4) +#define VENC_ETMG1 (VENC_REG_BASE + 0xE8) +#define VENC_ETMG2 (VENC_REG_BASE + 0xEC) +#define VENC_ETMG3 (VENC_REG_BASE + 0xF0) +#define VENC_DACSEL (VENC_REG_BASE + 0xF4) +#define VENC_ARGBX0 (VENC_REG_BASE + 0x100) +#define VENC_ARGBX1 (VENC_REG_BASE + 0x104) +#define VENC_ARGBX2 (VENC_REG_BASE + 0x108) +#define VENC_ARGBX3 (VENC_REG_BASE + 0x10C) +#define VENC_ARGBX4 (VENC_REG_BASE + 0x110) +#define VENC_DRGBX0 (VENC_REG_BASE + 0x114) +#define VENC_DRGBX1 (VENC_REG_BASE + 0x118) +#define VENC_DRGBX2 (VENC_REG_BASE + 0x11C) +#define VENC_DRGBX3 (VENC_REG_BASE + 0x120) +#define VENC_DRGBX4 (VENC_REG_BASE + 0x124) +#define VENC_VSTARTA (VENC_REG_BASE + 0x128) +#define VENC_OSDCLK0 (VENC_REG_BASE + 0x12C) +#define VENC_OSDCLK1 (VENC_REG_BASE + 0x130) +#define VENC_HVLDCL0 (VENC_REG_BASE + 0x134) +#define VENC_HVLDCL1 (VENC_REG_BASE + 0x138) +#define VENC_OSDHAD (VENC_REG_BASE + 0x13C) + +#define VID0 0 +#define VID1 1 +#define OSD0 3 +#define OSD1 4 + +/* VPBE On-Screen Display Subsystem Registers (OSD) */ +#define OSD_MODE (OSD_REG_BASE + 0x00) +#define OSD_VIDWINMD (OSD_REG_BASE + 0x04) +#define OSD_OSDWIN0MD (OSD_REG_BASE + 0x08) +#define OSD_OSDWIN1MD (OSD_REG_BASE + 0x0C) +#define OSD_OSDATRMD (OSD_REG_BASE + 0x0C) +#define OSD_RECTCUR (OSD_REG_BASE + 0x10) +#define OSD_WINOFST(i) (OSD_REG_BASE + 0x18 + (i)*0x4) +#define OSD_VIDWIN0OFST (OSD_REG_BASE + 0x18) +#define OSD_VIDWIN1OFST (OSD_REG_BASE + 0x1C) +#define OSD_OSDWIN0OFST (OSD_REG_BASE + 0x20) +#define OSD_OSDWIN1OFST (OSD_REG_BASE + 0x24) +#define OSD_WINADR(i) (OSD_REG_BASE + 0x2C + (i)*0x4) +#define OSD_VIDWIN0ADR (OSD_REG_BASE + 0x2C) +#define OSD_VIDWIN1ADR (OSD_REG_BASE + 0x30) +#define OSD_OSDWIN0ADR (OSD_REG_BASE + 0x38) +#define OSD_OSDWIN1ADR (OSD_REG_BASE + 0x3C) +#define OSD_BASEPX (OSD_REG_BASE + 0x40) +#define OSD_BASEPY (OSD_REG_BASE + 0x44) +#define OSD_WINXP(i) (OSD_REG_BASE + 0x48 + (i)*0x10) +#define OSD_WINYP(i) (OSD_REG_BASE + 0x4C + (i)*0x10) +#define OSD_WINXL(i) (OSD_REG_BASE + 0x50 + (i)*0x10) +#define OSD_WINYL(i) (OSD_REG_BASE + 0x54 + (i)*0x10) +#define OSD_VIDWIN0XP (OSD_REG_BASE + 0x48) +#define OSD_VIDWIN0YP (OSD_REG_BASE + 0x4C) +#define OSD_VIDWIN0XL (OSD_REG_BASE + 0x50) +#define OSD_VIDWIN0YL (OSD_REG_BASE + 0x54) +#define OSD_VIDWIN1XP (OSD_REG_BASE + 0x58) +#define OSD_VIDWIN1YP (OSD_REG_BASE + 0x5C) +#define OSD_VIDWIN1XL (OSD_REG_BASE + 0x60) +#define OSD_VIDWIN1YL (OSD_REG_BASE + 0x64) +#define OSD_OSDWIN0XP (OSD_REG_BASE + 0x68) +#define OSD_OSDWIN0YP (OSD_REG_BASE + 0x6C) +#define OSD_OSDWIN0XL (OSD_REG_BASE + 0x70) +#define OSD_OSDWIN0YL (OSD_REG_BASE + 0x74) +#define OSD_OSDWIN1XP (OSD_REG_BASE + 0x78) +#define OSD_OSDWIN1YP (OSD_REG_BASE + 0x7C) +#define OSD_OSDWIN1XL (OSD_REG_BASE + 0x80) +#define OSD_OSDWIN1YL (OSD_REG_BASE + 0x84) +#define OSD_CURXP (OSD_REG_BASE + 0x88) +#define OSD_CURYP (OSD_REG_BASE + 0x8C) +#define OSD_CURXL (OSD_REG_BASE + 0x90) +#define OSD_CURYL (OSD_REG_BASE + 0x94) +#define OSD_W0BMP01 (OSD_REG_BASE + 0xA0) +#define OSD_W0BMP23 (OSD_REG_BASE + 0xA4) +#define OSD_W0BMP45 (OSD_REG_BASE + 0xA8) +#define OSD_W0BMP67 (OSD_REG_BASE + 0xAC) +#define OSD_W0BMP89 (OSD_REG_BASE + 0xB0) +#define OSD_W0BMPAB (OSD_REG_BASE + 0xB4) +#define OSD_W0BMPCD (OSD_REG_BASE + 0xB8) +#define OSD_W0BMPEF (OSD_REG_BASE + 0xBC) +#define OSD_W1BMP0 (OSD_REG_BASE + 0xC0) +#define OSD_W1BMP2 (OSD_REG_BASE + 0xC4) +#define OSD_W1BMP4 (OSD_REG_BASE + 0xC8) +#define OSD_W1BMP6 (OSD_REG_BASE + 0xCC) +#define OSD_W1BMP8 (OSD_REG_BASE + 0xD0) +#define OSD_W1BMPA (OSD_REG_BASE + 0xD4) +#define OSD_W1BMPC (OSD_REG_BASE + 0xD8) +#define OSD_W1BMPE (OSD_REG_BASE + 0xDC) +#define OSD_TI_TES (OSD_REG_BASE + 0xE0) +#define OSD_MISCCT (OSD_REG_BASE + 0xE8) +#define OSD_CLUTRAMYC (OSD_REG_BASE + 0xEC) +#define OSD_CLUTRAMC (OSD_REG_BASE + 0xF0) +#define OSD_TRANSPVA (OSD_REG_BASE + 0xF0) +#define OSD_PPVWIN0AD (OSD_REG_BASE + 0xFC) + +/* bit definitions */ +#define VPBE_PCR_VENC_DIV (1 << 1) +#define VPBE_PCR_CLK_OFF (1 << 0) +#define VENC_VMOD_VDMD_SHIFT 12 +#define VENC_VMOD_VDMD_YCBCR16 0 +#define VENC_VMOD_VDMD_YCBCR8 1 +#define VENC_VMOD_VDMD_RGB666 2 +#define VENC_VMOD_VDMD_RGB8 3 +#define VENC_VMOD_VDMD_EPSON 4 +#define VENC_VMOD_VDMD_CASIO 5 +#define VENC_VMOD_VDMD_UDISPQVGA 6 +#define VENC_VMOD_VDMD_STNLCD 7 +#define VENC_VMOD_VDMD (7 << 12) +#define VENC_VMOD_ITLCL (1 << 11) +#define VENC_VMOD_ITLC (1 << 10) +#define VENC_VMOD_NSIT (1 << 9) +#define VENC_VMOD_HDMD (1 << 8) +#define VENC_VMOD_TVTYP (3 << 6) +#define VENC_VMOD_SLAVE (1 << 5) +#define VENC_VMOD_VMD (1 << 4) +#define VENC_VMOD_BLNK (1 << 3) +#define VENC_VMOD_VIE (1 << 1) +#define VENC_VMOD_VENC (1 << 0) +/* other VENC registers' bit positions not defined yet */ + +#define OSD_MODE_CS (1 << 15) +#define OSD_MODE_OVRSZ (1 << 14) +#define OSD_MODE_OHRSZ (1 << 13) +#define OSD_MODE_EF (1 << 12) +#define OSD_MODE_VVRSZ (1 << 11) +#define OSD_MODE_VHRSZ (1 << 10) +#define OSD_MODE_FSINV (1 << 9) +#define OSD_MODE_BCLUT (1 << 8) +#define OSD_MODE_CABG (0xff << 0) +#define OSD_MODE_CABG_SHIFT 0 + +#define OSD_VIDWINMD_VFINV (1 << 15) +#define OSD_VIDWINMD_V1EFC (1 << 14) +#define OSD_VIDWINMD_VHZ1 (3 << 12) +#define OSD_VIDWINMD_VHZ1_SHIFT 12 +#define OSD_VIDWINMD_VVZ1 (3 << 10) +#define OSD_VIDWINMD_VVZ1_SHIFT 10 +#define OSD_VIDWINMD_VFF1 (1 << 9) +#define OSD_VIDWINMD_ACT1 (1 << 8) +#define OSD_VIDWINMD_V0EFC (1 << 6) +#define OSD_VIDWINMD_VHZ0 (3 << 4) +#define OSD_VIDWINMD_VHZ0_SHIFT 4 +#define OSD_VIDWINMD_VVZ0 (3 << 2) +#define OSD_VIDWINMD_VVZ0_SHIFT 2 +#define OSD_VIDWINMD_VFF0 (1 << 1) +#define OSD_VIDWINMD_ACT0 (1 << 0) + +#define OSD_OSDWIN0MD_ATN0E (1 << 14) +#define OSD_OSDWIN0MD_RGB0E (1 << 13) +#define OSD_OSDWIN0MD_CLUTS0 (1 << 12) +#define OSD_OSDWIN0MD_OHZ0 (3 << 10) +#define OSD_OSDWIN0MD_OHZ0_SHIFT 10 +#define OSD_OSDWIN0MD_OVZ0 (3 << 8) +#define OSD_OSDWIN0MD_OVZ0_SHIFT 8 +#define OSD_OSDWIN0MD_BMW0 (3 << 6) +#define OSD_OSDWIN0MD_BMW0_SHIFT 6 +#define OSD_OSDWIN0MD_BLND0 (3 << 3) +#define OSD_OSDWIN0MD_BLND0_SHIFT 3 +#define OSD_OSDWIN0MD_TE0 (1 << 2) +#define OSD_OSDWIN0MD_OFF0 (1 << 1) +#define OSD_OSDWIN0MD_OACT0 (1 << 0) + +#define OSD_OSDWIN1MD_OASW (1 << 15) +#define OSD_OSDWIN1MD_ATN1E (1 << 14) +#define OSD_OSDWIN1MD_RGB1E (1 << 13) +#define OSD_OSDWIN1MD_CLUTS1 (1 << 12) +#define OSD_OSDWIN1MD_OHZ1 (3 << 10) +#define OSD_OSDWIN1MD_OHZ1_SHIFT 10 +#define OSD_OSDWIN1MD_OVZ1 (3 << 8) +#define OSD_OSDWIN1MD_OVZ1_SHIFT 8 +#define OSD_OSDWIN1MD_BMW1 (3 << 6) +#define OSD_OSDWIN1MD_BMW1_SHIFT 6 +#define OSD_OSDWIN1MD_BLND1 (3 << 3) +#define OSD_OSDWIN1MD_BLND1_SHIFT 3 +#define OSD_OSDWIN1MD_TE1 (1 << 2) +#define OSD_OSDWIN1MD_OFF1 (1 << 1) +#define OSD_OSDWIN1MD_OACT1 (1 << 0) + + +#define OSD_OSDATRMD_OASW (1 << 15) +#define OSD_OSDATRMD_OHZA (3 << 10) +#define OSD_OSDATRMD_OHZA_SHIFT 10 +#define OSD_OSDATRMD_OVZA (3 << 8) +#define OSD_OSDATRMD_OVZA_SHIFT 8 +#define OSD_OSDATRMD_BLNKINT (3 << 6) +#define OSD_OSDATRMD_BLNKINT_SHIFT 6 +#define OSD_OSDATRMD_OFFA (1 << 1) +#define OSD_OSDATRMD_BLNK (1 << 0) + +#define OSD_RECTCUR_RCAD (0xff << 8) +#define OSD_RECTCUR_RCAD_SHIFT 8 +#define OSD_RECTCUR_CLUTSR (1 << 7) +#define OSD_RECTCUR_RCHW (3 << 4) +#define OSD_RECTCUR_RCHW_SHIFT 4 +#define OSD_RECTCUR_RCVW (3 << 1) +#define OSD_RECTCUR_RCVW_SHIFT 1 +#define OSD_RECTCUR_RCACT (1 << 0) + +#define OSD_VIDWIN0OFST_V0LO (0x1ff << 0) +#define OSD_VIDWIN0OFST_V0LO_SHIFT 0 +#define OSD_VIDWIN1OFST_V1LO (0x1ff << 0) +#define OSD_VIDWIN1OFST_V1LO_SHIFT 0 +#define OSD_OSDWIN0OFST_O0LO (0x1ff << 0) +#define OSD_OSDWIN0OFST_O0LO_SHIFT 0 +#define OSD_OSDWIN1OFST_O1LO (0x1ff << 0) +#define OSD_OSDWIN1OFST_O1LO_SHIFT 0 +#define OSD_BASEPX_BPX (0x3ff << 0) +#define OSD_BASEPX_BPX_SHIFT 0 +#define OSD_BASEPY_BPY (0x1ff << 0) +#define OSD_BASEPY_BPY_SHIFT 0 +#define OSD_VIDWIN0XP_V0X (0x3ff << 0) +#define OSD_VIDWIN0XP_V0X_SHIFT 0 +#define OSD_VIDWIN0YP_V0Y (0x1ff << 0) +#define OSD_VIDWIN0YP_V0Y_SHIFT 0 +#define OSD_VIDWIN0XL_V0W (0xfff << 0) +#define OSD_VIDWIN0XL_V0W_SHIFT 0 +#define OSD_VIDWIN0YL_V0H (0x7ff << 0) +#define OSD_VIDWIN0YL_V0H_SHIFT 0 +#define OSD_VIDWIN1XP_V1X (0x3ff << 0) +#define OSD_VIDWIN1XP_V1X_SHIFT 0 +#define OSD_VIDWIN1YP_V1Y (0x1ff << 0) +#define OSD_VIDWIN1YP_V1Y_SHIFT 0 +#define OSD_VIDWIN1XL_V1W (0xfff << 0) +#define OSD_VIDWIN1XL_V1W_SHIFT 0 +#define OSD_VIDWIN1YL_V1H (0x7ff << 0) +#define OSD_VIDWIN1YL_V1H_SHIFT 0 +#define OSD_OSDWIN0XP_W0X (0x3ff << 0) +#define OSD_OSDWIN0XP_W0X_SHIFT 0 +#define OSD_OSDWIN0YP_W0Y (0x1ff << 0) +#define OSD_OSDWIN0YP_W0Y_SHIFT 0 +#define OSD_OSDWIN0XL_W0W (0xfff << 0) +#define OSD_OSDWIN0XL_W0W_SHIFT 0 +#define OSD_OSDWIN0YL_W0H (0x7ff << 0) +#define OSD_OSDWIN0YL_W0H_SHIFT 0 +#define OSD_OSDWIN1XP_W1X (0x3ff << 0) +#define OSD_OSDWIN1XP_W1X_SHIFT 0 +#define OSD_OSDWIN1YP_W1Y (0x1ff << 0) +#define OSD_OSDWIN1YP_W1Y_SHIFT 0 +#define OSD_OSDWIN1XL_W1W (0xfff << 0) +#define OSD_OSDWIN1XL_W1W_SHIFT 0 +#define OSD_OSDWIN1YL_W1H (0x7ff << 0) +#define OSD_OSDWIN1YL_W1H_SHIFT 0 +#define OSD_CURXP_RCSX (0x3ff << 0) +#define OSD_CURXP_RCSX_SHIFT 0 +#define OSD_CURYP_RCSY (0x1ff << 0) +#define OSD_CURYP_RCSY_SHIFT 0 +#define OSD_CURYL_RCSH (0x7ff << 0) +#define OSD_CURYL_RCSH_SHIFT 0 +#define OSD_W0BMP01_PAL01 (0xff << 8) +#define OSD_W0BMP01_PAL01_SHIFT 8 +#define OSD_W0BMP01_PAL00 (0xff << 0) +#define OSD_W0BMP01_PAL00_SHIFT 0 +#define OSD_W0BMP23_PAL03 (0xff << 8) +#define OSD_W0BMP23_PAL03_SHIFT 8 +#define OSD_W0BMP23_PAL02 (0xff << 0) +#define OSD_W0BMP23_PAL02_SHIFT 0 +#define OSD_W0BMP45_PAL05 (0xff << 8) +#define OSD_W0BMP45_PAL05_SHIFT 8 +#define OSD_W0BMP45_PAL04 (0xff << 0) +#define OSD_W0BMP45_PAL04_SHIFT 0 +#define OSD_W0BMP67_PAL07 (0xff << 8) +#define OSD_W0BMP67_PAL07_SHIFT 8 +#define OSD_W0BMP67_PAL06 (0xff << 0) +#define OSD_W0BMP67_PAL06_SHIFT 0 +#define OSD_W0BMP89_PAL09 (0xff << 8) +#define OSD_W0BMP89_PAL09_SHIFT 8 +#define OSD_W0BMP89_PAL08 (0xff << 0) +#define OSD_W0BMP89_PAL08_SHIFT 0 +#define OSD_W0BMPAB_PAL11 (0xff << 8) +#define OSD_W0BMPAB_PAL11_SHIFT 8 +#define OSD_W0BMPAB_PAL10 (0xff << 0) +#define OSD_W0BMPAB_PAL10_SHIFT 0 +#define OSD_W0BMPCD_PAL13 (0xff << 8) +#define OSD_W0BMPCD_PAL13_SHIFT 8 +#define OSD_W0BMPCD_PAL12 (0xff << 0) +#define OSD_W0BMPCD_PAL12_SHIFT 0 +#define OSD_W0BMPEF_PAL15 (0xff << 8) +#define OSD_W0BMPEF_PAL15_SHIFT 8 +#define OSD_W0BMPEF_PAL14 (0xff << 0) +#define OSD_W0BMPEF_PAL14_SHIFT 0 +#define OSD_W1BMP0_PAL01 (0xff << 8) +#define OSD_W1BMP0_PAL01_SHIFT 8 +#define OSD_W1BMP0_PAL00 (0xff << 0) +#define OSD_W1BMP0_PAL00_SHIFT 0 +#define OSD_W1BMP2_PAL03 (0xff << 8) +#define OSD_W1BMP2_PAL03_SHIFT 8 +#define OSD_W1BMP2_PAL02 (0xff << 0) +#define OSD_W1BMP2_PAL02_SHIFT 0 +#define OSD_W1BMP4_PAL05 (0xff << 8) +#define OSD_W1BMP4_PAL05_SHIFT 8 +#define OSD_W1BMP4_PAL04 (0xff << 0) +#define OSD_W1BMP4_PAL04_SHIFT 0 +#define OSD_W1BMP6_PAL07 (0xff << 8) +#define OSD_W1BMP6_PAL07_SHIFT 8 +#define OSD_W1BMP6_PAL06 (0xff << 0) +#define OSD_W1BMP6_PAL06_SHIFT 0 +#define OSD_W1BMP8_PAL09 (0xff << 8) +#define OSD_W1BMP8_PAL09_SHIFT 8 +#define OSD_W1BMP8_PAL08 (0xff << 0) +#define OSD_W1BMP8_PAL08_SHIFT 0 +#define OSD_W1BMPA_PAL11 (0xff << 8) +#define OSD_W1BMPA_PAL11_SHIFT 8 +#define OSD_W1BMPA_PAL10 (0xff << 0) +#define OSD_W1BMPA_PAL10_SHIFT 0 +#define OSD_W1BMPC_PAL13 (0xff << 8) +#define OSD_W1BMPC_PAL13_SHIFT 8 +#define OSD_W1BMPC_PAL12 (0xff << 0) +#define OSD_W1BMPC_PAL12_SHIFT 0 +#define OSD_W1BMPE_PAL15 (0xff << 8) +#define OSD_W1BMPE_PAL15_SHIFT 8 +#define OSD_W1BMPE_PAL14 (0xff << 0) +#define OSD_W1BMPE_PAL14_SHIFT 0 + +#define OSD_MISCCT_RGBEN (1 << 7) +#define OSD_MISCCT_RGBWIN (1 << 6) +#define OSD_MISCCT_TMON (1 << 5) +#define OSD_MISCCT_RSEL (1 << 4) +#define OSD_MISCCT_CPBSY (1 << 3) +#define OSD_MISCCT_PPSW (1 << 2) +#define OSD_MISCCT_PPRV (1 << 1) + +#define OSD_CLUTRAMY_Y (0xff << 8) +#define OSD_CLUTRAMY_Y_SHIFT 8 +#define OSD_CLUTRAMY_CB (0xff << 0) +#define OSD_CLUTRAMY_CB_SHIFT 0 +#define OSD_CLUTRAM_CR (0xff << 8) +#define OSD_CLUTRAM_CR_SHIFT 8 +#define OSD_CLUTRAM_CADDR (0xff << 0) +#define OSD_CLUTRAM_CADDR_SHIFT 0 +#define OSD_TRANSPVA_RGBTRANS (0xff << 0) +#define OSD_TRANSPVA_RGBTRANS_SHIFT 0 + + +#define LCD 0 +#define NTSC 1 +#define PAL 2 + +#define COMPOSITE 1 +#define SVIDEO 2 +#define COMPONENT 3 +#define RGB 4 + +/* define the custom FBIO_WAITFORVSYNC ioctl */ +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) +#define FBIO_SETATTRIBUTE _IOW('F', 0x21, struct fb_fillrect) +#define FBIO_SETPOSX _IOW('F', 0x22, u_int32_t) +#define FBIO_SETPOSY _IOW('F', 0x23, u_int32_t) +struct zoom_params +{ + u_int32_t window_id; + u_int32_t zoom_h; + u_int32_t zoom_v; +}; +#define FBIO_SETZOOM _IOW('F', 0x24, struct zoom_params) +#define FBIO_GETSTD _IOR('F', 0x25, u_int32_t) +#endif /* _DAVINCIFB_H_ */ diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c index 40eccfe9e358..2406b096f04a 100644 --- a/sound/soc/davinci/davinci-sffsdr.c +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -29,7 +29,7 @@ #include <asm/plat-sffsdr/sffsdr-fpga.h> #endif -#include <mach/mcbsp.h> +#include <mach/asp.h> #include <mach/edma.h> #include "../codecs/pcm3008.h" @@ -63,8 +63,13 @@ static int sffsdr_hw_params(struct snd_pcm_substream *substream, } #endif - /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT); + /* Set cpu DAI configuration: + * CLKX and CLKR are the inputs for the Sample Rate Generator. + * FSX and FSR are outputs, driven by the sample Rate Generator. */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_RIGHT_J | + SND_SOC_DAIFMT_CBM_CFS | + SND_SOC_DAIFMT_IB_NF); if (ret < 0) return ret; @@ -115,15 +120,15 @@ static struct snd_soc_device sffsdr_snd_devdata = { static struct resource sffsdr_snd_resources[] = { { - .start = DAVINCI_MCBSP_BASE, - .end = DAVINCI_MCBSP_BASE + SZ_8K - 1, + .start = DAVINCI_ASP0_BASE, + .end = DAVINCI_ASP0_BASE + SZ_8K - 1, .flags = IORESOURCE_MEM, }, }; static struct evm_snd_platform_data sffsdr_snd_data = { - .tx_dma_ch = DAVINCI_DMA_MCBSP_TX, - .rx_dma_ch = DAVINCI_DMA_MCBSP_RX, + .tx_dma_ch = DAVINCI_DMA_ASP0_TX, + .rx_dma_ch = DAVINCI_DMA_ASP0_RX, }; static struct platform_device *sffsdr_snd_device; |