diff options
94 files changed, 51686 insertions, 0 deletions
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index a2af24dd3b9..5b81df73186 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -206,4 +206,6 @@ config UX500_DB_DUMP source "arch/arm/mach-ux500/pm/Kconfig" source "arch/arm/mach-ux500/test/Kconfig" +source "arch/arm/mach-ux500/Kconfig-arch" + endif diff --git a/arch/arm/mach-ux500/Kconfig-arch b/arch/arm/mach-ux500/Kconfig-arch new file mode 100644 index 00000000000..45fc2716814 --- /dev/null +++ b/arch/arm/mach-ux500/Kconfig-arch @@ -0,0 +1,56 @@ +config U8500_SECURE + bool "Support for running in Secure mode" + default n + help + Build the kernel to run in Secure mode. + +#Configuration for MCDE setup + +if FB_MCDE + +menu "Display setup" + +choice + prompt "TV output type" + default U8500_TV_OUTPUT_AV8100 + help + Select the source of TV output to use + +config U8500_TV_OUTPUT_AV8100 + bool "AV8100 (HDMI/CVBS)" + depends on MCDE_DISPLAY_AV8100 + +config U8500_TV_OUTPUT_AB8500 + bool "AB8500 (CVBS)" + depends on MCDE_DISPLAY_AB8500_DENC + +endchoice + +choice + prompt "Color depth" + depends on DISPLAY_GENERIC_PRIMARY + default MCDE_DISPLAY_PRIMARY_16BPP + help + Select color depth for primary display + +config MCDE_DISPLAY_PRIMARY_16BPP + bool "16 bpp" + help + 16 bpp color depth + +config MCDE_DISPLAY_PRIMARY_32BPP + bool "32 bpp" + help + 32 bpp color depth + +endchoice + +config DISPLAY_AV8100_TRIPPLE_BUFFER + bool "Enable tripple buffer for HDMI display" + depends on MCDE_DISPLAY_AV8100 + help + Say yes to enable tripple buffer. You'll get double buffer otherwise + +endmenu + +endif diff --git a/arch/arm/mach-ux500/board-mop500-mcde.c b/arch/arm/mach-ux500/board-mop500-mcde.c new file mode 100644 index 00000000000..3d8c8fc4852 --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-mcde.c @@ -0,0 +1,559 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/mfd/ab8500/denc.h> +#include <linux/workqueue.h> +#include <linux/dispdev.h> +#include <linux/compdev.h> +#include <asm/mach-types.h> +#include <linux/clk.h> +#include <mach/devices.h> +#include <video/av8100.h> +#include <video/mcde_display.h> +#include <video/mcde_display-vuib500-dpi.h> +#include <video/mcde_display-sony_acx424akp_dsi.h> +#include <video/mcde_display-av8100.h> +#include <video/mcde_display-ab8500.h> +#include <video/mcde_fb.h> +#include <video/mcde_dss.h> +#include <plat/pincfg.h> +#include "pins-db8500.h" +#include "pins.h" +#include "board-mop500.h" + +#define DSI_UNIT_INTERVAL_0 0x9 +#define DSI_UNIT_INTERVAL_1 0x9 +#define DSI_UNIT_INTERVAL_2 0x5 + +#define DSI_PLL_FREQ_HZ 840320000 +/* Based on PLL DDR Freq at 798,72 MHz */ +#define HDMI_FREQ_HZ 33280000 +#define TV_FREQ_HZ 38400000 + +#ifdef CONFIG_U8500_TV_OUTPUT_AV8100 +/* The initialization of hdmi disp driver must be delayed in order to + * ensure that inputclk will be available (needed by hdmi hw) */ +static struct delayed_work work_dispreg_hdmi; +#define DISPREG_HDMI_DELAY 6000 +#endif + +enum { + PRIMARY_DISPLAY_ID, + SECONDARY_DISPLAY_ID, + FICTIVE_DISPLAY_ID, + AV8100_DISPLAY_ID, + AB8500_DISPLAY_ID, + MCDE_NR_OF_DISPLAYS +}; + +static int display_initialized_during_boot; + +static int __init startup_graphics_setup(char *str) +{ + + if (get_option(&str, &display_initialized_during_boot) != 1) + display_initialized_during_boot = 0; + + switch (display_initialized_during_boot) { + case 1: + pr_info("Startup graphics support\n"); + break; + case 0: + default: + pr_info("No startup graphics supported\n"); + break; + }; + + return 1; +} +__setup("startup_graphics=", startup_graphics_setup); + +#if defined(CONFIG_U8500_TV_OUTPUT_AV8100) || \ + defined(CONFIG_U8500_TV_OUTPUT_AB8500) +static struct mcde_col_transform rgb_2_yCbCr_transform = { + .matrix = { + {0x0042, 0x0081, 0x0019}, + {0xffda, 0xffb6, 0x0070}, + {0x0070, 0xffa2, 0xffee}, + }, + .offset = {0x10, 0x80, 0x80}, +}; +#endif + +static struct mcde_port samsung_s6d16d0_port0 = { + .sync_src = MCDE_SYNCSRC_BTA, + .frame_trig = MCDE_TRIG_SW, +}; + +static struct mcde_display_dsi_platform_data samsung_s6d16d0_pdata0 = { + .link = 0, +}; + +static struct mcde_display_device samsung_s6d16d0_display0 = { + .name = "samsung_s6d16d0", + .id = PRIMARY_DISPLAY_ID, + .port = &samsung_s6d16d0_port0, + .chnl_id = MCDE_CHNL_A, + .fifo = MCDE_FIFO_A, + .default_pixel_format = MCDE_OVLYPIXFMT_RGBA8888, + .dev = { + .platform_data = &samsung_s6d16d0_pdata0, + }, +}; + +static struct mcde_port sony_port0 = { + .link = 0, + .sync_src = MCDE_SYNCSRC_BTA, + .frame_trig = MCDE_TRIG_HW, +}; + +static struct mcde_display_sony_acx424akp_platform_data + sony_acx424akp_display0_pdata = { + .reset_gpio = HREFV60_DISP1_RST_GPIO, +}; + +static struct mcde_display_device sony_acx424akp_display0 = { + .name = "mcde_disp_sony_acx424akp", + .id = PRIMARY_DISPLAY_ID, + .port = &sony_port0, + .chnl_id = MCDE_CHNL_A, + .fifo = MCDE_FIFO_A, + .orientation = MCDE_DISPLAY_ROT_0, + .default_pixel_format = MCDE_OVLYPIXFMT_RGBA8888, + .dev = { + .platform_data = &sony_acx424akp_display0_pdata, + }, +}; + +static struct mcde_port samsung_s6d16d0_port1 = { + .sync_src = MCDE_SYNCSRC_BTA, + .frame_trig = MCDE_TRIG_SW, +}; + +static struct mcde_display_dsi_platform_data samsung_s6d16d0_pdata1 = { + .link = 1, +}; + +static struct mcde_display_device samsung_s6d16d0_display1 = { + .name = "samsung_s6d16d0", + .id = SECONDARY_DISPLAY_ID, + .port = &samsung_s6d16d0_port1, + .chnl_id = MCDE_CHNL_C1, + .fifo = MCDE_FIFO_C1, + .orientation = MCDE_DISPLAY_ROT_90_CCW, + .default_pixel_format = MCDE_OVLYPIXFMT_RGB565, + .dev = { + .platform_data = &samsung_s6d16d0_pdata1, + }, +}; + +#ifdef CONFIG_U8500_TV_OUTPUT_AB8500 +static struct mcde_port port_tvout1 = { + .type = MCDE_PORTTYPE_DPI, + .pixel_format = MCDE_PORTPIXFMT_DPI_24BPP, + .link = 1, /* channel B */ + .sync_src = MCDE_SYNCSRC_OFF, + .update_auto_trig = true, + .phy = { + .dpi = { + .bus_width = 4, /* DDR mode */ + .tv_mode = true, + .clock_div = MCDE_PORT_DPI_NO_CLOCK_DIV, + }, + }, +}; + +static struct ab8500_display_platform_data ab8500_display_pdata = { + .nr_regulators = 2, + .regulator_id = {"vtvout", "vcc-N2158"}, + .rgb_2_yCbCr_transform = &rgb_2_yCbCr_transform, +}; + +static struct ux500_pins *tvout_pins; + +static int ab8500_platform_enable(struct mcde_display_device *ddev) +{ + int res = 0; + + if (!tvout_pins) { + tvout_pins = ux500_pins_get("mcde-tvout"); + if (!tvout_pins) + return -EINVAL; + } + + dev_dbg(&ddev->dev, "%s\n", __func__); + res = ux500_pins_enable(tvout_pins); + if (res != 0) + goto failed; + + return res; + +failed: + dev_warn(&ddev->dev, "Failure during %s\n", __func__); + return res; +} + +static int ab8500_platform_disable(struct mcde_display_device *ddev) +{ + int res; + + dev_dbg(&ddev->dev, "%s\n", __func__); + + res = ux500_pins_disable(tvout_pins); + if (res != 0) + goto failed; + return res; + +failed: + dev_warn(&ddev->dev, "Failure during %s\n", __func__); + return res; +} + +static struct mcde_display_device tvout_ab8500_display = { + .name = "mcde_tv_ab8500", + .id = AB8500_DISPLAY_ID, + .port = &port_tvout1, + .chnl_id = MCDE_CHNL_B, + .fifo = MCDE_FIFO_B, + .default_pixel_format = MCDE_OVLYPIXFMT_RGB565, + .native_x_res = 720, + .native_y_res = 576, + .dev = { + .platform_data = &ab8500_display_pdata, + }, + + /* + * We might need to describe the std here: + * - there are different PAL / NTSC formats (do they require MCDE + * settings?) + */ + .platform_enable = ab8500_platform_enable, + .platform_disable = ab8500_platform_disable, +}; +#endif + +#ifdef CONFIG_U8500_TV_OUTPUT_AV8100 + +#if defined(CONFIG_AV8100_HWTRIG_INT) + #define AV8100_SYNC_SRC MCDE_SYNCSRC_TE0 +#elif defined(CONFIG_AV8100_HWTRIG_I2SDAT3) + #define AV8100_SYNC_SRC MCDE_SYNCSRC_TE1 +#elif defined(CONFIG_AV8100_HWTRIG_DSI_TE) + #define AV8100_SYNC_SRC MCDE_SYNCSRC_TE_POLLING +#else + #define AV8100_SYNC_SRC MCDE_SYNCSRC_OFF +#endif +static struct mcde_port av8100_port2 = { + .type = MCDE_PORTTYPE_DSI, + .mode = MCDE_PORTMODE_CMD, + .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP, + .ifc = 1, + .link = 2, + .sync_src = AV8100_SYNC_SRC, + .update_auto_trig = true, + .phy = { + .dsi = { + .num_data_lanes = 2, + .ui = DSI_UNIT_INTERVAL_2, + }, + }, + .hdmi_sdtv_switch = HDMI_SWITCH, +}; + +static struct mcde_display_hdmi_platform_data av8100_hdmi_pdata = { + .cvbs_regulator_id = "vcc-N2158", + .rgb_2_yCbCr_transform = &rgb_2_yCbCr_transform, +}; + +static struct ux500_pins *av8100_pins; +static int av8100_platform_enable(struct mcde_display_device *ddev) +{ + int res; + + dev_dbg(&ddev->dev, "%s\n", __func__); + if (!av8100_pins) { + av8100_pins = ux500_pins_get("av8100-hdmi"); + if (!av8100_pins) { + res = -EINVAL; + goto failed; + } + } + + res = ux500_pins_enable(av8100_pins); + if (res != 0) + goto failed; + + return res; + +failed: + dev_warn(&ddev->dev, "Failure during %s\n", __func__); + return res; +} + +static int av8100_platform_disable(struct mcde_display_device *ddev) +{ + int res; + + dev_dbg(&ddev->dev, "%s\n", __func__); + + res = ux500_pins_disable(av8100_pins); + if (res != 0) + goto failed; + return res; + +failed: + dev_warn(&ddev->dev, "Failure during %s\n", __func__); + return res; +} + +static struct mcde_display_device av8100_hdmi = { + .name = "av8100_hdmi", + .id = AV8100_DISPLAY_ID, + .port = &av8100_port2, + .chnl_id = MCDE_CHNL_B, + .fifo = MCDE_FIFO_B, + .default_pixel_format = MCDE_OVLYPIXFMT_RGB565, + .native_x_res = 1280, + .native_y_res = 720, + .dev = { + .platform_data = &av8100_hdmi_pdata, + }, + .platform_enable = av8100_platform_enable, + .platform_disable = av8100_platform_disable, +}; + +static void delayed_work_dispreg_hdmi(struct work_struct *ptr) +{ + if (mcde_display_device_register(&av8100_hdmi)) + pr_warning("Failed to register av8100_hdmi\n"); +} +#endif /* CONFIG_U8500_TV_OUTPUT_AV8100 */ + +/* +* This function will create the framebuffer for the display that is registered. +*/ +static int display_postregistered_callback(struct notifier_block *nb, + unsigned long event, void *dev) +{ + struct mcde_display_device *ddev = dev; + u16 width, height; + u16 virtual_height; + struct fb_info *fbi; +#if defined(CONFIG_DISPDEV) || defined(CONFIG_COMPDEV) + struct mcde_fb *mfb; +#endif + + if (event != MCDE_DSS_EVENT_DISPLAY_REGISTERED) + return 0; + + if (ddev->id < 0 || ddev->id >= MCDE_NR_OF_DISPLAYS) + return 0; + + mcde_dss_get_native_resolution(ddev, &width, &height); + virtual_height = height * 2; + +#ifndef CONFIG_MCDE_DISPLAY_HDMI_FB_AUTO_CREATE + if (ddev->id == AV8100_DISPLAY_ID) + goto out; +#endif + + /* Create frame buffer */ + fbi = mcde_fb_create(ddev, width, height, width, virtual_height, + ddev->default_pixel_format, FB_ROTATE_UR); + if (IS_ERR(fbi)) { + dev_warn(&ddev->dev, + "Failed to create fb for display %s\n", ddev->name); + goto display_postregistered_callback_err; + } else { + dev_info(&ddev->dev, "Framebuffer created (%s)\n", ddev->name); + } + +#ifdef CONFIG_DISPDEV + mfb = to_mcde_fb(fbi); + + /* Create a dispdev overlay for this display */ + if (dispdev_create(ddev, true, mfb->ovlys[0]) < 0) { + dev_warn(&ddev->dev, + "Failed to create disp for display %s\n", ddev->name); + goto display_postregistered_callback_err; + } else { + dev_info(&ddev->dev, "Disp dev created for (%s)\n", ddev->name); + } +#endif + +#ifdef CONFIG_COMPDEV + mfb = to_mcde_fb(fbi); + /* Create a compdev overlay for this display */ + if (compdev_create(ddev, mfb->ovlys[0], true) < 0) { + dev_warn(&ddev->dev, + "Failed to create compdev for display %s\n", + ddev->name); + goto display_postregistered_callback_err; + } else { + dev_info(&ddev->dev, "compdev created for (%s)\n", + ddev->name); + } +#endif + +out: + return 0; + +display_postregistered_callback_err: + return -1; +} + +static struct notifier_block display_nb = { + .notifier_call = display_postregistered_callback, +}; + +/* +* This function is used to refresh the display (lcd, hdmi, tvout) with black +* when the framebuffer is registered. +* The main display will not be updated if startup graphics is displayed +* from u-boot. +*/ +static int framebuffer_postregistered_callback(struct notifier_block *nb, + unsigned long event, void *data) +{ + int ret = 0; + struct fb_event *event_data = data; + struct fb_info *info; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + struct mcde_fb *mfb; + + if (event != FB_EVENT_FB_REGISTERED) + return 0; + + if (!event_data) + return 0; + + info = event_data->info; + mfb = to_mcde_fb(info); + if (mfb->id == 0 && display_initialized_during_boot) + goto out; + + var = info->var; + fix = info->fix; + var.yoffset = var.yoffset ? 0 : var.yres; + if (info->fbops->fb_pan_display) + ret = info->fbops->fb_pan_display(&var, info); +out: + return ret; +} + +static struct notifier_block framebuffer_nb = { + .notifier_call = framebuffer_postregistered_callback, +}; + +static int __init init_display_devices(void) +{ + int ret; + + if (!cpu_is_u8500()) + return 0; + + ret = fb_register_client(&framebuffer_nb); + if (ret) + pr_warning("Failed to register framebuffer notifier\n"); + + (void)mcde_dss_register_notifier(&display_nb); + + /* Set powermode to STANDBY if startup graphics is executed */ + if (display_initialized_during_boot) { + samsung_s6d16d0_display0.power_mode = MCDE_DISPLAY_PM_STANDBY; + sony_acx424akp_display0.power_mode = MCDE_DISPLAY_PM_STANDBY; + } + + /* Display reset GPIO is different depending on reference boards */ + if (machine_is_hrefv60() || machine_is_u8520() || machine_is_u9540()) { + samsung_s6d16d0_pdata0.reset_gpio = HREFV60_DISP1_RST_GPIO; + samsung_s6d16d0_pdata1.reset_gpio = HREFV60_DISP2_RST_GPIO; + } else { + samsung_s6d16d0_pdata0.reset_gpio = MOP500_DISP1_RST_GPIO; + samsung_s6d16d0_pdata1.reset_gpio = MOP500_DISP2_RST_GPIO; + } + + /* Initialize all needed clocks*/ + if (!display_initialized_during_boot) { + struct clk *clk_dsi_pll; + struct clk *clk_hdmi; + struct clk *clk_tv; + + /* + * The TV CLK is used as parent for the + * DSI LP clock. + */ + clk_tv = clk_get(&u8500_mcde_device.dev, "tv"); + if (TV_FREQ_HZ != clk_round_rate(clk_tv, TV_FREQ_HZ)) + pr_warning("%s: TV_CLK freq differs %ld\n", __func__, + clk_round_rate(clk_tv, TV_FREQ_HZ)); + clk_set_rate(clk_tv, TV_FREQ_HZ); + clk_put(clk_tv); + + /* + * The HDMI CLK is used as parent for the + * DSI HS clock. + */ + clk_hdmi = clk_get(&u8500_mcde_device.dev, "hdmi"); + if (HDMI_FREQ_HZ != clk_round_rate(clk_hdmi, HDMI_FREQ_HZ)) + pr_warning("%s: HDMI freq differs %ld\n", __func__, + clk_round_rate(clk_hdmi, HDMI_FREQ_HZ)); + clk_set_rate(clk_hdmi, HDMI_FREQ_HZ); + clk_put(clk_hdmi); + + /* + * The DSI PLL CLK is used as DSI PLL for direct freq for + * link 2. Link 0/1 is then divided with 1/2/4 from this freq. + */ + clk_dsi_pll = clk_get(&u8500_mcde_device.dev, "dsihs2"); + if (DSI_PLL_FREQ_HZ != clk_round_rate(clk_dsi_pll, + DSI_PLL_FREQ_HZ)) + pr_warning("%s: DSI_PLL freq differs %ld\n", __func__, + clk_round_rate(clk_dsi_pll, DSI_PLL_FREQ_HZ)); + clk_set_rate(clk_dsi_pll, DSI_PLL_FREQ_HZ); + clk_put(clk_dsi_pll); + } + + /* Not all STUIBs supports VSYNC, disable vsync for STUIB */ + if (uib_is_stuib()) { + /* Samsung display on STUIB */ + samsung_s6d16d0_display0.port->sync_src = MCDE_SYNCSRC_OFF; + samsung_s6d16d0_display0.orientation = MCDE_DISPLAY_ROT_90_CCW; + (void)mcde_display_device_register(&samsung_s6d16d0_display0); + } else if (uib_is_u8500uib()) { + /* Samsung display on U8500UIB */ + samsung_s6d16d0_display0.orientation = MCDE_DISPLAY_ROT_90_CW; + (void)mcde_display_device_register(&samsung_s6d16d0_display0); + } else if (uib_is_u8500uibr3()) { + /* Sony display on U8500UIBV3 */ + (void)mcde_display_device_register(&sony_acx424akp_display0); + } + else + pr_warning("Unknown UI board\n"); + + /* Display reset GPIO is different depending on reference boards */ + if (uib_is_stuib()) + (void)mcde_display_device_register(&samsung_s6d16d0_display1); + +#if defined(CONFIG_U8500_TV_OUTPUT_AV8100) + INIT_DELAYED_WORK_DEFERRABLE(&work_dispreg_hdmi, + delayed_work_dispreg_hdmi); + schedule_delayed_work(&work_dispreg_hdmi, + msecs_to_jiffies(DISPREG_HDMI_DELAY)); +#elif defined(CONFIG_U8500_TV_OUTPUT_AB8500) + (void)mcde_display_device_register(&tvout_ab8500_display); +#endif + + return 0; +} +module_init(init_display_devices); diff --git a/arch/arm/mach-ux500/board-u5500-mcde.c b/arch/arm/mach-ux500/board-u5500-mcde.c new file mode 100644 index 00000000000..906b5572229 --- /dev/null +++ b/arch/arm/mach-ux500/board-u5500-mcde.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/dispdev.h> +#include <video/av8100.h> +#include <asm/mach-types.h> +#include <video/mcde_display.h> +#include <video/mcde_display-generic_dsi.h> +#include <video/mcde_display-sony_acx424akp_dsi.h> +#include <video/mcde_display-av8100.h> +#include <video/mcde_fb.h> +#include <video/mcde_dss.h> + +#define DSI_UNIT_INTERVAL_0 0xA +#define DSI_UNIT_INTERVAL_2 0x5 + +/* The initialization of hdmi disp driver must be delayed in order to + * ensure that inputclk will be available (needed by hdmi hw) */ +static struct delayed_work work_dispreg_hdmi; +#define DISPREG_HDMI_DELAY 6000 + +enum { + PRIMARY_DISPLAY_ID, + AV8100_DISPLAY_ID, + MCDE_NR_OF_DISPLAYS +}; + +static int display_initialized_during_boot; + +static int __init startup_graphics_setup(char *str) +{ + + if (get_option(&str, &display_initialized_during_boot) != 1) + display_initialized_during_boot = 0; + + switch (display_initialized_during_boot) { + case 1: + pr_info("Startup graphics support\n"); + break; + case 0: + default: + pr_info("No startup graphics supported\n"); + break; + }; + + return 1; +} +__setup("startup_graphics=", startup_graphics_setup); + +static struct mcde_col_transform rgb_2_yCbCr_transform = { + .matrix = { + {0x0042, 0x0081, 0x0019}, + {0xffda, 0xffb6, 0x0070}, + {0x0070, 0xffa2, 0xffee}, + }, + .offset = {0x10, 0x80, 0x80}, +}; + +static struct mcde_port sony_port0 = { + .link = 0, + .sync_src = MCDE_SYNCSRC_BTA, + .frame_trig = MCDE_TRIG_SW, +}; + +static struct mcde_display_sony_acx424akp_platform_data \ + sony_acx424akp_display0_pdata = { + .reset_gpio = 226, +}; + +static struct mcde_display_device sony_acx424akp_display0 = { + .name = "mcde_disp_sony_acx424akp", + .id = PRIMARY_DISPLAY_ID, + .port = &sony_port0, + .chnl_id = MCDE_CHNL_A, + .fifo = MCDE_FIFO_A, + .default_pixel_format = MCDE_OVLYPIXFMT_RGBA8888, + .dev = { + .platform_data = &sony_acx424akp_display0_pdata, + }, +}; + +#if defined(CONFIG_AV8100_HWTRIG_INT) + #define AV8100_SYNC_SRC MCDE_SYNCSRC_TE0 +#elif defined(CONFIG_AV8100_HWTRIG_I2SDAT3) + #define AV8100_SYNC_SRC MCDE_SYNCSRC_TE1 +#elif defined(CONFIG_AV8100_HWTRIG_DSI_TE) + #define AV8100_SYNC_SRC MCDE_SYNCSRC_TE_POLLING +#else + #define AV8100_SYNC_SRC MCDE_SYNCSRC_OFF +#endif +static struct mcde_port av8100_port2 = { + .type = MCDE_PORTTYPE_DSI, + .mode = MCDE_PORTMODE_CMD, + .pixel_format = MCDE_PORTPIXFMT_DSI_24BPP, + .link = 1, + .sync_src = AV8100_SYNC_SRC, + .update_auto_trig = true, + .phy = { + .dsi = { + .num_data_lanes = 2, + .ui = DSI_UNIT_INTERVAL_2, + }, + }, + .hdmi_sdtv_switch = HDMI_SWITCH, +}; + +static struct mcde_display_hdmi_platform_data av8100_hdmi_pdata = { + .rgb_2_yCbCr_transform = &rgb_2_yCbCr_transform, +}; + +static struct mcde_display_device av8100_hdmi = { + .name = "av8100_hdmi", + .id = AV8100_DISPLAY_ID, + .port = &av8100_port2, + .chnl_id = MCDE_CHNL_B, + .fifo = MCDE_FIFO_B, + .default_pixel_format = MCDE_OVLYPIXFMT_RGB888, + .native_x_res = 1280, + .native_y_res = 720, + .dev = { + .platform_data = &av8100_hdmi_pdata, + }, +}; + +static void delayed_work_dispreg_hdmi(struct work_struct *ptr) +{ + if (mcde_display_device_register(&av8100_hdmi)) + pr_warning("Failed to register av8100_hdmi\n"); +} + +/* +* This function will create the framebuffer for the display that is registered. +*/ +static int display_postregistered_callback(struct notifier_block *nb, + unsigned long event, void *dev) +{ + struct mcde_display_device *ddev = dev; + u16 width, height; + u16 virtual_height; + u32 rotate = FB_ROTATE_UR; + struct fb_info *fbi; +#ifdef CONFIG_DISPDEV + struct mcde_fb *mfb; +#endif + + if (event != MCDE_DSS_EVENT_DISPLAY_REGISTERED) + return 0; + + if (ddev->id < PRIMARY_DISPLAY_ID || ddev->id >= MCDE_NR_OF_DISPLAYS) + return 0; + + mcde_dss_get_native_resolution(ddev, &width, &height); + + virtual_height = height * 2; + +#ifndef CONFIG_MCDE_DISPLAY_HDMI_FB_AUTO_CREATE + if (ddev->id == AV8100_DISPLAY_ID) + goto out; +#endif + + /* Create frame buffer */ + fbi = mcde_fb_create(ddev, width, height, width, virtual_height, + ddev->default_pixel_format, rotate); + if (IS_ERR(fbi)) { + dev_warn(&ddev->dev, + "Failed to create fb for display %s\n", ddev->name); + goto display_postregistered_callback_err; + } else { + dev_info(&ddev->dev, "Framebuffer created (%s)\n", ddev->name); + } + +#ifdef CONFIG_DISPDEV + mfb = to_mcde_fb(fbi); + + /* Create a dispdev overlay for this display */ + if (dispdev_create(ddev, true, mfb->ovlys[0]) < 0) { + dev_warn(&ddev->dev, + "Failed to create disp for display %s\n", ddev->name); + goto display_postregistered_callback_err; + } else { + dev_info(&ddev->dev, "Disp dev created for (%s)\n", ddev->name); + } +#endif + +out: + return 0; + +display_postregistered_callback_err: + return -1; +} + +static struct notifier_block display_nb = { + .notifier_call = display_postregistered_callback, +}; + +/* +* This function is used to refresh the display (lcd, hdmi, tvout) with black +* when the framebuffer is registered. +* The main display will not be updated if startup graphics is displayed +* from u-boot. +*/ +static int framebuffer_postregistered_callback(struct notifier_block *nb, + unsigned long event, void *data) +{ + int ret = 0; + struct fb_event *event_data = data; + struct fb_info *info; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + struct mcde_fb *mfb; + + if (event != FB_EVENT_FB_REGISTERED) + return 0; + + if (!event_data) + return 0; + + info = event_data->info; + mfb = to_mcde_fb(info); + if (mfb->id == 0 && display_initialized_during_boot) + goto out; + + var = info->var; + fix = info->fix; + var.yoffset = var.yoffset ? 0 : var.yres; + if (info->fbops->fb_pan_display) + ret = info->fbops->fb_pan_display(&var, info); +out: + return ret; +} + +static struct notifier_block framebuffer_nb = { + .notifier_call = framebuffer_postregistered_callback, +}; + +int __init init_u5500_display_devices(void) +{ + int ret; + + if (!cpu_is_u5500()) + return 0; + + ret = fb_register_client(&framebuffer_nb); + if (ret) + pr_warning("Failed to register framebuffer notifier\n"); + + (void)mcde_dss_register_notifier(&display_nb); + + if (display_initialized_during_boot) + sony_acx424akp_display0.power_mode = MCDE_DISPLAY_PM_STANDBY; + + (void)mcde_display_device_register(&sony_acx424akp_display0); + + INIT_DELAYED_WORK_DEFERRABLE(&work_dispreg_hdmi, + delayed_work_dispreg_hdmi); + schedule_delayed_work(&work_dispreg_hdmi, + msecs_to_jiffies(DISPREG_HDMI_DELAY)); + + return 0; +} +module_init(init_u5500_display_devices); + diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 1a9ae1647b0..f92560ef750 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -461,6 +461,40 @@ 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 CLONEDEV + bool "Display cloning device" + depends on FB_MCDE && HWMEM && COMPDEV + default n + help + This driver provides a way to clone content between two compdev + devices. + +config CLONEDEV_DEBUG + bool "Display cloning device debug" + depends on CLONEDEV + default n + help + This driver provides a way to clone content between two compdev + devices. + 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..2741a01610f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -48,6 +48,9 @@ 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_CLONEDEV) += clonedev/ 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/clonedev/Makefile b/drivers/misc/clonedev/Makefile new file mode 100644 index 00000000000..f84859dd3ee --- /dev/null +++ b/drivers/misc/clonedev/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_CLONEDEV) += clonedev.o + +ifdef CONFIG_CLONEDEV_DEBUG +EXTRA_CFLAGS += -DDEBUG +endif diff --git a/drivers/misc/clonedev/clonedev.c b/drivers/misc/clonedev/clonedev.c new file mode 100644 index 00000000000..d3b770fd324 --- /dev/null +++ b/drivers/misc/clonedev/clonedev.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * Device for display cloning on external output. + * + * Author: 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/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/clonedev.h> + +#include <linux/compdev.h> +#include <linux/mm.h> +#include <video/mcde.h> + +static LIST_HEAD(dev_list); +static DEFINE_MUTEX(dev_list_lock); + +struct clonedev { + struct mutex lock; + struct miscdevice mdev; + struct list_head list; + bool open; + struct compdev *src_compdev; + struct compdev *dst_compdev; + bool overlay_case; + struct compdev_size dst_size; + struct compdev_scene_info s_info; +}; + +static void best_fit(struct compdev_rect *src_rect, + struct compdev_size *dst_size, + struct compdev_img *img) +{ + /* aspect ratio in 26.6 fixed point */ + int aspect = 1; + int dst_w; + int dst_h; + + if (img->rotation == COMPDEV_ROT_90_CCW || + img->rotation == COMPDEV_ROT_270_CCW) + aspect = (src_rect->height << 6) / src_rect->width; + else + aspect = (src_rect->width << 6) / src_rect->height; + + dst_w = aspect * dst_size->height >> 6; + dst_h = dst_size->height; + img->dst_rect.y = 0; + + if (dst_w > dst_size->width) { + /* + * Destination rectangle too wide. + * Clamp to image width. Keep aspect ratio. + */ + dst_h = (dst_size->width << 6) / aspect; + dst_w = dst_size->width; + } + + /* center the image */ + if (dst_w < dst_size->width) { + int offset = (dst_size->width - dst_w) / 2; + img->dst_rect.x = offset; + } + + if (dst_h < dst_size->height) { + int offset = (dst_size->height - dst_h) / 2; + img->dst_rect.y = offset; + } + + img->dst_rect.width = dst_w; + img->dst_rect.height = dst_h; +} + +static int clonedev_open(struct inode *inode, struct file *file) +{ + struct clonedev *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 clonedev_release(struct inode *inode, struct file *file) +{ + struct clonedev *cd = NULL; + + 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; + + cd->open = false; + return 0; +} + +static long clonedev_ioctl(struct file *file, + unsigned int cmd, + unsigned long arg) +{ + int ret; + struct clonedev *cd = (struct clonedev *)file->private_data; + + mutex_lock(&cd->lock); + + switch (cmd) { + case CLONEDEV_SET_MODE_IOC: + /* TODO: Get the user data */ + + break; + + default: + ret = -ENOSYS; + } + + mutex_unlock(&cd->lock); + + return ret; +} + +static const struct file_operations clonedev_fops = { + .open = clonedev_open, + .release = clonedev_release, + .unlocked_ioctl = clonedev_ioctl, +}; + +static void init_clonedev(struct clonedev *cd, const char *name) +{ + mutex_init(&cd->lock); + INIT_LIST_HEAD(&cd->list); + + cd->mdev.minor = MISC_DYNAMIC_MINOR; + cd->mdev.name = name; + cd->mdev.fops = &clonedev_fops; +} + +static void clonedev_post_buffer_callback(void *data, + struct compdev_img *cb_img) +{ + struct clonedev *cd = (struct clonedev *)data; + + mutex_lock(&cd->lock); + + if (!cd->overlay_case || (cd->overlay_case && + (cb_img->flags & COMPDEV_OVERLAY_FLAG))) { + struct compdev_img img; + + img = *cb_img; + + if (img.flags & COMPDEV_BYPASS_FLAG) + img.flags &= ~COMPDEV_BYPASS_FLAG; + + if (cd->overlay_case) + img.rotation = cd->s_info.ovly_rotation; + else + img.rotation = cd->s_info.fb_rotation; + + best_fit(&img.src_rect, &cd->dst_size, &img); + + compdev_post_buffer(cd->dst_compdev, &img); + } + mutex_unlock(&cd->lock); +} + +static void clonedev_post_scene_info_callback(void *data, + struct compdev_scene_info *s_info) +{ + struct clonedev *cd = (struct clonedev *)data; + + mutex_lock(&cd->lock); + if (s_info->img_count > 1) + cd->overlay_case = true; + else + cd->overlay_case = false; + + cd->s_info = *s_info; + cd->s_info.img_count = 1; + compdev_post_scene_info(cd->dst_compdev, &cd->s_info); + mutex_unlock(&cd->lock); +} + +int clonedev_create(void) +{ + int ret; + struct clonedev *cd; + + static int counter; + char name[10]; + + cd = kzalloc(sizeof(struct clonedev), GFP_KERNEL); + if (!cd) + return -ENOMEM; + + snprintf(name, sizeof(name), "%s%d", CLONEDEV_DEFAULT_DEVICE_PREFIX, + counter++); + init_clonedev(cd, name); + + 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); + + mutex_lock(&cd->lock); + + compdev_get(0, &cd->src_compdev); + compdev_get(1, &cd->dst_compdev); + compdev_get_size(cd->dst_compdev, &cd->dst_size); + + compdev_register_listener_callbacks(cd->src_compdev, (void *)cd, + &clonedev_post_buffer_callback, + &clonedev_post_scene_info_callback); + + mutex_unlock(&cd->lock); + goto out; + +fail_register_misc: + kfree(cd); +out: + return ret; +} + +void clonedev_destroy(void) +{ + struct clonedev *cd; + struct clonedev *tmp; + + mutex_lock(&dev_list_lock); + list_for_each_entry_safe(cd, tmp, &dev_list, list) { + compdev_put(cd->src_compdev); + compdev_put(cd->dst_compdev); + compdev_deregister_callbacks(cd->src_compdev); + list_del(&cd->list); + misc_deregister(&cd->mdev); + kfree(cd); + break; + } + mutex_unlock(&dev_list_lock); +} + +static void clonedev_destroy_all(void) +{ + struct clonedev *cd; + struct clonedev *tmp; + + mutex_lock(&dev_list_lock); + list_for_each_entry_safe(cd, tmp, &dev_list, list) { + list_del(&cd->list); + misc_deregister(&cd->mdev); + kfree(cd); + } + mutex_unlock(&dev_list_lock); + + mutex_destroy(&dev_list_lock); +} + +static int __init clonedev_init(void) +{ + pr_info("%s\n", __func__); + + mutex_init(&dev_list_lock); + + return 0; +} +module_init(clonedev_init); + +static void __exit clonedev_exit(void) +{ + clonedev_destroy_all(); + pr_info("%s\n", __func__); +} +module_exit(clonedev_exit); + +MODULE_AUTHOR("Per-Daniel Olsson <per-daniel.olsson@stericsson.com>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Device for display cloning on external output"); + diff --git a/drivers/misc/compdev/Makefile b/drivers/misc/compdev/Makefile new file mode 100644 index 00000000000..b8385848712 --- /dev/null +++ b/drivers/misc/compdev/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_COMPDEV) += compdev.o + +ifdef CONFIG_COMPDEV_DEBUG +EXTRA_CFLAGS += -DDEBUG +endif + diff --git a/drivers/misc/compdev/compdev.c b/drivers/misc/compdev/compdev.c new file mode 100644 index 00000000000..d929a02c565 --- /dev/null +++ b/drivers/misc/compdev/compdev.c @@ -0,0 +1,1381 @@ +/* + * 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/sched.h> + +#include <linux/compdev.h> +#include <linux/hwmem.h> +#include <linux/mm.h> +#include <video/mcde_dss.h> +#include <video/b2r2_blt.h> +#include <linux/workqueue.h> +#include <linux/completion.h> + +#define BUFFER_CACHE_DEPTH 2 +#define NUM_COMPDEV_BUFS 2 + +static LIST_HEAD(dev_list); +static DEFINE_MUTEX(dev_list_lock); +static int dev_counter; + +struct compdev_buffer { + struct hwmem_alloc *alloc; + enum compdev_ptr_type type; + u32 size; + u32 paddr; /* if pinned */ +}; + +struct compdev_img_internal { + struct compdev_img img; + u32 ref_count; +}; + +struct compdev_blt_work { + struct work_struct work; + struct compdev_img *src_img; + struct compdev_img_internal *dst_img; + int blt_handle; + bool mcde_rotation; + struct device *dev; +}; + +struct compdev_post_callback_work { + struct work_struct work; + struct compdev_img *img; + post_buffer_callback pb_cb; + void *cb_data; + struct device *dev; +}; + +struct buffer_cache_context { + struct compdev_img_internal + *img[BUFFER_CACHE_DEPTH]; + u8 index; + u8 unused_counter; + struct device *dev; +}; + +struct dss_context { + struct device *dev; + 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; + int blt_handle; + u8 temp_img_count; + struct compdev_img_internal *temp_img[NUM_COMPDEV_BUFS]; + struct buffer_cache_context cache_ctx; +}; + +struct compdev { + struct mutex lock; + struct miscdevice mdev; + struct device *dev; + struct list_head list; + struct dss_context dss_ctx; + u16 ref_count; + struct workqueue_struct *worker_thread; + int dev_index; + post_buffer_callback pb_cb; + post_scene_info_callback si_cb; + struct compdev_scene_info s_info; + u8 sync_count; + u8 image_count; + struct compdev_img *images[NUM_COMPDEV_BUFS]; + struct completion fence; + void *cb_data; + bool mcde_rotation; +}; + +static struct compdev *compdevs[MAX_NBR_OF_COMPDEVS]; + +static int compdev_post_buffers_dss(struct dss_context *dss_ctx, + struct compdev_img *img1, struct compdev_img *img2); + + +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; + } + 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->dss_ctx.ovly[i]); + if (cd->dss_ctx.ovly_buffer[i].paddr && + cd->dss_ctx.ovly_buffer[i].type == + COMPDEV_PTR_HWMEM_BUF_NAME_OFFSET) + hwmem_unpin(cd->dss_ctx.ovly_buffer[i].alloc); + + cd->dss_ctx.ovly_buffer[i].alloc = NULL; + cd->dss_ctx.ovly_buffer[i].size = 0; + cd->dss_ctx.ovly_buffer[i].paddr = 0; + } + + 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 dss_context *dss_ctx) +{ + 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(dss_ctx->dev, + "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(dss_ctx->dev, + "Invalid_mem overlay, %d\n", ret); + goto invalid_mem; + } + ret = hwmem_pin(buffer->alloc, &mem_chunk, &mem_chunk_length); + if (ret) { + dev_warn(dss_ctx->dev, + "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(dss_ctx->dev, + "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 = img->dst_rect.width; + info.dirty.h = img->dst_rect.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 dss_context *dss_ctx, + 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(dss_ctx->ddev, &vmode); + if ((dss_ctx->display_rotation + rotation) % 180) { + vmode.xres = dss_ctx->phy_size.height; + vmode.yres = dss_ctx->phy_size.width; + } else { + vmode.xres = dss_ctx->phy_size.width; + vmode.yres = dss_ctx->phy_size.height; + } + + /* Set rotation */ + ret = mcde_dss_set_rotation(dss_ctx->ddev, + (dss_ctx->display_rotation + rotation) % 360); + if (ret != 0) + goto exit; + + ret = mcde_dss_set_video_mode(dss_ctx->ddev, &vmode); + if (ret != 0) + goto exit; + + + /* Apply */ + ret = mcde_dss_apply_channel(dss_ctx->ddev); +exit: + return ret; +} + +static int release_prev_frame(struct dss_context *dss_ctx) +{ + int ret = 0; + int i; + + /* Handle unpin of previous buffers */ + for (i = 0; i < NUM_COMPDEV_BUFS; i++) { + if (dss_ctx->ovly_buffer[i].type == + COMPDEV_PTR_HWMEM_BUF_NAME_OFFSET && + dss_ctx->ovly_buffer[i].paddr != 0) { + hwmem_unpin(dss_ctx->ovly_buffer[i].alloc); + hwmem_release(dss_ctx->ovly_buffer[i].alloc); + } + dss_ctx->ovly_buffer[i].alloc = NULL; + dss_ctx->ovly_buffer[i].size = 0; + dss_ctx->ovly_buffer[i].paddr = 0; + } + return ret; + +} + +static enum b2r2_blt_fmt compdev_to_blt_format(enum compdev_fmt fmt) +{ + switch (fmt) { + case COMPDEV_FMT_RGBA8888: + return B2R2_BLT_FMT_32_BIT_ABGR8888; + case COMPDEV_FMT_RGB888: + return B2R2_BLT_FMT_24_BIT_RGB888; + case COMPDEV_FMT_RGB565: + return B2R2_BLT_FMT_16_BIT_RGB565; + case COMPDEV_FMT_YUV422: + return B2R2_BLT_FMT_CB_Y_CR_Y; + case COMPDEV_FMT_YCBCR42XMBN: + return B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE; + case COMPDEV_FMT_YUV420_SP: + return B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR; + case COMPDEV_FMT_YVU420_SP: + return B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR; + case COMPDEV_FMT_YUV420_P: + return B2R2_BLT_FMT_YUV420_PACKED_PLANAR; + default: + return B2R2_BLT_FMT_UNUSED; + } +} + +static enum b2r2_blt_transform to_blt_transform + (enum compdev_rotation compdev_rot) +{ + switch (compdev_rot) { + case COMPDEV_ROT_0: + return B2R2_BLT_TRANSFORM_NONE; + case COMPDEV_ROT_90_CCW: + return B2R2_BLT_TRANSFORM_CCW_ROT_90; + case COMPDEV_ROT_180: + return B2R2_BLT_TRANSFORM_CCW_ROT_180; + case COMPDEV_ROT_270_CCW: + return B2R2_BLT_TRANSFORM_CCW_ROT_90; + default: + return B2R2_BLT_TRANSFORM_NONE; + } +} + +static u32 get_stride(u32 width, enum compdev_fmt fmt) +{ + u32 stride = 0; + switch (fmt) { + case COMPDEV_FMT_RGB565: + stride = width * 2; + break; + case COMPDEV_FMT_RGB888: + stride = width * 3; + break; + case COMPDEV_FMT_RGBX8888: + stride = width * 4; + break; + case COMPDEV_FMT_RGBA8888: + stride = width * 4; + break; + case COMPDEV_FMT_YUV422: + stride = width * 2; + break; + case COMPDEV_FMT_YCBCR42XMBN: + case COMPDEV_FMT_YUV420_SP: + case COMPDEV_FMT_YVU420_SP: + case COMPDEV_FMT_YUV420_P: + stride = width; + break; + } + + /* The display controller requires 8 byte aligned strides */ + if (stride % 8) + stride += 8 - (stride % 8); + + return stride; +} + +static int alloc_comp_internal_img(enum compdev_fmt fmt, + u16 width, u16 height, struct compdev_img_internal **img_pp) +{ + struct hwmem_alloc *alloc; + int name; + u32 size; + u32 stride; + struct compdev_img_internal *img; + + stride = get_stride(width, fmt); + size = stride * height; + size = PAGE_ALIGN(size); + + img = kzalloc(sizeof(struct compdev_img_internal), GFP_KERNEL); + + if (!img) + return -ENOMEM; + + 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)) { + kfree(img); + img = NULL; + return PTR_ERR(alloc); + } + + name = hwmem_get_name(alloc); + if (name < 0) { + kfree(img); + img = NULL; + hwmem_release(alloc); + return name; + } + + img->img.height = height; + img->img.width = width; + img->img.fmt = fmt; + img->img.pitch = stride; + img->img.buf.hwmem_buf_name = name; + img->img.buf.type = COMPDEV_PTR_HWMEM_BUF_NAME_OFFSET; + img->img.buf.offset = 0; + img->img.buf.len = size; + + img->ref_count = 1; + + *img_pp = img; + + return 0; +} + +static void free_comp_img_buf(struct compdev_img_internal *img, + struct device *dev) +{ + dev_dbg(dev, "%s\n", __func__); + + if (img != NULL && img->ref_count) { + img->ref_count--; + if (img->ref_count == 0) { + struct hwmem_alloc *alloc; + if (img->img.buf.hwmem_buf_name > 0) { + alloc = hwmem_resolve_by_name( + img->img.buf.hwmem_buf_name); + if (IS_ERR(alloc)) { + dev_err(dev, "%s: Error getting Alloc " + "from HWMEM\n", __func__); + return; + } + /* Double release needed */ + hwmem_release(alloc); + hwmem_release(alloc); + } + kfree(img); + } + } +} + +struct compdev_img_internal *compdev_buffer_cache_get_image( + struct buffer_cache_context *cache_ctx, enum compdev_fmt fmt, + u16 width, u16 height) +{ + int i; + struct compdev_img_internal *img = NULL; + + dev_dbg(cache_ctx->dev, "%s\n", __func__); + + /* First check for a cache hit */ + if (cache_ctx->unused_counter > 0) { + u8 active_index = cache_ctx->index; + struct compdev_img_internal *temp = + cache_ctx->img[active_index]; + if (temp != NULL && temp->img.fmt == fmt && + temp->img.width == width && + temp->img.height == height) { + img = temp; + cache_ctx->unused_counter = 0; + } + } + /* Check if there was a cache hit */ + if (img == NULL) { + /* Create new buffers and release old */ + for (i = 0; i < BUFFER_CACHE_DEPTH; i++) { + if (cache_ctx->img[i]) { + free_comp_img_buf(cache_ctx->img[i], + cache_ctx->dev); + cache_ctx->img[i] = NULL; + } + cache_ctx->index = 0; + if (alloc_comp_internal_img(fmt, width, height, + &cache_ctx->img[i])) + dev_err(cache_ctx->dev, + "%s: Allocation error\n", + __func__); + } + img = cache_ctx->img[0]; + } + + if (img != NULL) { + img->ref_count++; + cache_ctx->unused_counter = 0; + cache_ctx->index++; + if (cache_ctx->index >= BUFFER_CACHE_DEPTH) + cache_ctx->index = 0; + } + + return img; +} + +static void compdev_buffer_cache_mark_frame + (struct buffer_cache_context *cache_ctx) +{ + if (cache_ctx->unused_counter < 2) + cache_ctx->unused_counter++; + if (cache_ctx->unused_counter == 2) { + int i; + for (i = 0; i < BUFFER_CACHE_DEPTH; i++) { + if (cache_ctx->img[i]) { + free_comp_img_buf(cache_ctx->img[i], + cache_ctx->dev); + cache_ctx->img[i] = NULL; + } + } + } +} + +static bool check_hw_format(enum compdev_fmt fmt) +{ + if (fmt == COMPDEV_FMT_RGB565 || + fmt == COMPDEV_FMT_RGB888 || + fmt == COMPDEV_FMT_RGBA8888 || + fmt == COMPDEV_FMT_RGBX8888 || + fmt == COMPDEV_FMT_YUV422) + return true; + else + return false; +} + +static enum compdev_fmt find_compatible_fmt(enum compdev_fmt fmt, bool rotation) +{ + if (!rotation) { + switch (fmt) { + case COMPDEV_FMT_RGB565: + case COMPDEV_FMT_RGB888: + case COMPDEV_FMT_RGBA8888: + case COMPDEV_FMT_RGBX8888: + return fmt; + case COMPDEV_FMT_YUV422: + case COMPDEV_FMT_YCBCR42XMBN: + case COMPDEV_FMT_YUV420_SP: + case COMPDEV_FMT_YVU420_SP: + case COMPDEV_FMT_YUV420_P: + return COMPDEV_FMT_YUV422; + default: + return COMPDEV_FMT_RGBA8888; + } + } else { + switch (fmt) { + case COMPDEV_FMT_RGB565: + case COMPDEV_FMT_RGB888: + case COMPDEV_FMT_RGBA8888: + case COMPDEV_FMT_RGBX8888: + return fmt; + case COMPDEV_FMT_YUV422: + case COMPDEV_FMT_YCBCR42XMBN: + case COMPDEV_FMT_YUV420_SP: + case COMPDEV_FMT_YVU420_SP: + case COMPDEV_FMT_YUV420_P: + return COMPDEV_FMT_RGB888; + default: + return COMPDEV_FMT_RGBA8888; + } + } +} + +static void compdev_callback_worker_function(struct work_struct *work) +{ + struct compdev_post_callback_work *cb_work = + (struct compdev_post_callback_work *)work; + + if (cb_work->pb_cb != NULL) + cb_work->pb_cb(cb_work->cb_data, cb_work->img); +} +static void compdev_blt_worker_function(struct work_struct *work) +{ + struct compdev_blt_work *blt_work = (struct compdev_blt_work *)work; + struct compdev_img *src_img; + struct compdev_img *dst_img; + struct b2r2_blt_req req; + int req_id; + + dev_dbg(blt_work->dev, "%s\n", __func__); + + src_img = blt_work->src_img; + dst_img = &blt_work->dst_img->img; + + memset(&req, 0, sizeof(req)); + req.size = sizeof(req); + + if (src_img->buf.type == COMPDEV_PTR_PHYSICAL) { + req.src_img.buf.type = B2R2_BLT_PTR_PHYSICAL; + req.src_img.buf.fd = src_img->buf.fd; + } else { + struct hwmem_alloc *alloc; + + req.src_img.buf.type = B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET; + req.src_img.buf.hwmem_buf_name = src_img->buf.hwmem_buf_name; + + alloc = hwmem_resolve_by_name(src_img->buf.hwmem_buf_name); + if (IS_ERR(alloc)) { + dev_warn(blt_work->dev, + "HWMEM resolve failed\n"); + } + hwmem_set_access(alloc, + HWMEM_ACCESS_READ | HWMEM_ACCESS_IMPORT, + task_tgid_nr(current)); + hwmem_release(alloc); + } + req.src_img.pitch = src_img->pitch; + req.src_img.buf.offset = src_img->buf.offset; + req.src_img.buf.len = src_img->buf.len; + req.src_img.fmt = compdev_to_blt_format(src_img->fmt); + req.src_img.width = src_img->width; + req.src_img.height = src_img->height; + + req.src_rect.x = src_img->src_rect.x; + req.src_rect.y = src_img->src_rect.y; + req.src_rect.width = src_img->src_rect.width; + req.src_rect.height = src_img->src_rect.height; + + if (dst_img->buf.type == COMPDEV_PTR_PHYSICAL) { + req.dst_img.buf.type = B2R2_BLT_PTR_PHYSICAL; + req.dst_img.buf.fd = dst_img->buf.fd; + } else { + req.dst_img.buf.type = B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET; + req.dst_img.buf.hwmem_buf_name = dst_img->buf.hwmem_buf_name; + } + req.dst_img.pitch = dst_img->pitch; + req.dst_img.buf.offset = dst_img->buf.offset; + req.dst_img.buf.len = dst_img->buf.len; + req.dst_img.fmt = compdev_to_blt_format(dst_img->fmt); + req.dst_img.width = dst_img->width; + req.dst_img.height = dst_img->height; + + if (blt_work->mcde_rotation) + req.transform = B2R2_BLT_TRANSFORM_NONE; + else + req.transform = to_blt_transform(src_img->rotation); + req.dst_rect.x = 0; + req.dst_rect.y = 0; + req.dst_rect.width = src_img->dst_rect.width; + req.dst_rect.height = src_img->dst_rect.height; + + req.global_alpha = 0xff; + req.flags = B2R2_BLT_FLAG_DITHER; + + req_id = b2r2_blt_request(blt_work->blt_handle, &req); + + if (b2r2_blt_synch(blt_work->blt_handle, req_id) < 0) { + dev_err(blt_work->dev, + "%s: Could not perform b2r2_blt_synch", + __func__); + } + + dst_img->src_rect.x = 0; + dst_img->src_rect.x = 0; + dst_img->src_rect.width = dst_img->width; + dst_img->src_rect.height = dst_img->height; + + dst_img->dst_rect.x = src_img->dst_rect.x; + dst_img->dst_rect.y = src_img->dst_rect.y; + dst_img->dst_rect.width = src_img->dst_rect.width; + dst_img->dst_rect.height = src_img->dst_rect.height; + + dst_img->rotation = src_img->rotation; +} + +static int compdev_post_buffer_locked(struct compdev *cd, + struct compdev_img *src_img) +{ + int ret = 0; + int i; + bool transform_needed = false; + struct compdev_img *resulting_img; + struct compdev_blt_work blt_work; + struct compdev_post_callback_work cb_work; + bool callback_work = false; + bool bypass_case = false; + + dev_dbg(cd->dev, "%s\n", __func__); + + /* Free potential temp buffers */ + for (i = 0; i < cd->dss_ctx.temp_img_count; i++) + free_comp_img_buf(cd->dss_ctx.temp_img[i], cd->dev); + cd->dss_ctx.temp_img_count = 0; + + /* Check for bypass images */ + if (src_img->flags & COMPDEV_BYPASS_FLAG) + bypass_case = true; + + /* Handle callback */ + if (cd->pb_cb != NULL) { + callback_work = true; + INIT_WORK((struct work_struct *)&cb_work, + compdev_callback_worker_function); + cb_work.img = src_img; + cb_work.pb_cb = cd->pb_cb; + cb_work.cb_data = cd->cb_data; + cb_work.dev = cd->dev; + queue_work(cd->worker_thread, (struct work_struct *)&cb_work); + } + + if (!bypass_case) { + /* Determine if transform is needed */ + /* First check scaling */ + if ((src_img->rotation == COMPDEV_ROT_0 || + src_img->rotation == COMPDEV_ROT_180) && + (src_img->src_rect.width != src_img->dst_rect.width || + src_img->src_rect.height != src_img->dst_rect.height)) + transform_needed = true; + else if ((src_img->rotation == COMPDEV_ROT_90_CCW || + src_img->rotation == COMPDEV_ROT_270_CCW) && + (src_img->src_rect.width != src_img->dst_rect.height || + src_img->src_rect.height != src_img->dst_rect.width)) + transform_needed = true; + + if (!transform_needed && check_hw_format(src_img->fmt) == false) + transform_needed = true; + + if (transform_needed) { + u16 width = 0; + u16 height = 0; + enum compdev_fmt fmt; + + INIT_WORK((struct work_struct *)&blt_work, + compdev_blt_worker_function); + + if (cd->dss_ctx.blt_handle == 0) { + dev_dbg(cd->dev, "%s: B2R2 opened\n", __func__); + cd->dss_ctx.blt_handle = b2r2_blt_open(); + if (cd->dss_ctx.blt_handle < 0) { + dev_warn(cd->dev, + "%s(%d): Failed to " + "open b2r2 device\n", + __func__, __LINE__); + } + } + blt_work.blt_handle = cd->dss_ctx.blt_handle; + blt_work.src_img = src_img; + blt_work.mcde_rotation = cd->mcde_rotation; + + width = src_img->dst_rect.width; + height = src_img->dst_rect.height; + + fmt = find_compatible_fmt(src_img->fmt, + (!cd->mcde_rotation) && + (src_img->rotation != COMPDEV_ROT_0)); + + blt_work.dst_img = compdev_buffer_cache_get_image + (&cd->dss_ctx.cache_ctx, + fmt, width, height); + + blt_work.dst_img->img.flags = src_img->flags; + blt_work.dev = cd->dev; + + queue_work(cd->worker_thread, + (struct work_struct *)&blt_work); + flush_work_sync((struct work_struct *)&blt_work); + + resulting_img = &blt_work.dst_img->img; + + cd->dss_ctx.temp_img[cd->dss_ctx.temp_img_count] = + blt_work.dst_img; + cd->dss_ctx.temp_img_count++; + + } else { + resulting_img = src_img; + } + + if (!cd->mcde_rotation) + resulting_img->rotation = COMPDEV_ROT_0; + + cd->images[cd->image_count] = resulting_img; + cd->image_count++; + + /* make sure that a potential callback has returned */ + if (callback_work) + flush_work_sync((struct work_struct *)&cb_work); + + if (cd->sync_count > 1) { + cd->sync_count--; + mutex_unlock(&cd->lock); + /* Wait for fence */ + wait_for_completion(&cd->fence); + mutex_lock(&cd->lock); + } else { + struct compdev_img *img1 = NULL; + struct compdev_img *img2 = NULL; + + if (cd->sync_count) + cd->sync_count--; + + img1 = cd->images[0]; + if (cd->image_count) + img2 = cd->images[1]; + + /* Do the refresh */ + compdev_post_buffers_dss(&cd->dss_ctx, img1, img2); + compdev_buffer_cache_mark_frame + (&cd->dss_ctx.cache_ctx); + + if (cd->s_info.img_count > 1) { + /* Releasing fence */ + complete(&cd->fence); + } + + cd->sync_count = 0; + cd->image_count = 0; + cd->images[0] = NULL; + cd->images[1] = NULL; + } + } else { + /* make sure that a potential callback has returned */ + if (callback_work) + flush_work_sync((struct work_struct *)&cb_work); + } + + return ret; +} + +static int compdev_post_buffers_dss(struct dss_context *dss_ctx, + struct compdev_img *img1, struct compdev_img *img2) +{ + int ret = 0; + int i = 0; + + struct compdev_img *fb_img = NULL; + struct compdev_img *ovly_img = NULL; + + /* Unpin the previous frame */ + release_prev_frame(dss_ctx); + + /* Set channel rotation */ + if (img1 != NULL && + (dss_ctx->current_buffer_rotation != img1->rotation)) { + if (compdev_update_rotation(dss_ctx, img1->rotation) != 0) + dev_warn(dss_ctx->dev, + "Failed to update MCDE rotation " + "(img1->rotation = %d), %d\n", + img1->rotation, ret); + else + dss_ctx->current_buffer_rotation = img1->rotation; + } + + if ((img1 != NULL) && (img1->flags & COMPDEV_OVERLAY_FLAG)) + ovly_img = img1; + else if (img1 != NULL) + fb_img = img1; + + + if ((img2 != NULL) && (img2->flags & COMPDEV_OVERLAY_FLAG)) + ovly_img = img2; + else if (img2 != NULL) + fb_img = img2; + + /* Handle buffers */ + if (fb_img != NULL) { + ret = compdev_setup_ovly(fb_img, + &dss_ctx->ovly_buffer[i], dss_ctx->ovly[0], 1, dss_ctx); + if (ret) + dev_warn(dss_ctx->dev, + "Failed to setup overlay[%d], %d\n", 0, ret); + i++; + } else { + disable_overlay(dss_ctx->ovly[0]); + } + + + if (ovly_img != NULL) { + ret = compdev_setup_ovly(ovly_img, + &dss_ctx->ovly_buffer[i], dss_ctx->ovly[1], 0, dss_ctx); + if (ret) + dev_warn(dss_ctx->dev, + "Failed to setup overlay[%d], %d\n", 1, ret); + } else { + disable_overlay(dss_ctx->ovly[1]); + } + + /* Do the display update */ + mcde_dss_update_overlay(dss_ctx->ovly[0], true); + + return ret; +} + +static int compdev_post_scene_info_locked(struct compdev *cd, + struct compdev_scene_info *s_info) +{ + int ret = 0; + + dev_dbg(cd->dev, "%s\n", __func__); + + cd->s_info = *s_info; + cd->sync_count = cd->s_info.img_count; + + /* always complete the fence in case someone is hanging incorrectly. */ + complete(&cd->fence); + init_completion(&cd->fence); + + /* Handle callback */ + if (cd->si_cb != NULL) { + mutex_unlock(&cd->lock); + cd->si_cb(cd->cb_data, s_info); + mutex_lock(&cd->lock); + } + return ret; +} + + +static int compdev_get_size_locked(struct dss_context *dss_ctx, + struct compdev_size *size) +{ + int ret = 0; + if ((dss_ctx->display_rotation) % 180) { + size->height = dss_ctx->phy_size.width; + size->width = dss_ctx->phy_size.height; + } else { + size->height = dss_ctx->phy_size.height; + size->width = dss_ctx->phy_size.width; + } + + return ret; +} + +static int compdev_get_listener_state_locked(struct compdev *cd, + enum compdev_listener_state *state) +{ + int ret = 0; + + *state = COMPDEV_LISTENER_OFF; + if (cd->pb_cb != NULL) + *state = COMPDEV_LISTENER_ON; + 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_img img; + struct compdev_scene_info s_info; + + mutex_lock(&cd->lock); + + switch (cmd) { + case COMPDEV_GET_SIZE_IOC: + { + struct compdev_size tmp; + compdev_get_size_locked(&cd->dss_ctx, &tmp); + ret = copy_to_user((void __user *)arg, &tmp, + sizeof(tmp)); + if (ret) + ret = -EFAULT; + } + break; + case COMPDEV_GET_LISTENER_STATE_IOC: + { + enum compdev_listener_state state; + compdev_get_listener_state_locked(cd, &state); + ret = copy_to_user((void __user *)arg, &state, + sizeof(state)); + if (ret) + ret = -EFAULT; + } + break; + case COMPDEV_POST_BUFFER_IOC: + memset(&img, 0, sizeof(img)); + /* Get the user data */ + if (copy_from_user(&img, (void *)arg, sizeof(img))) { + dev_warn(cd->dev, + "%s: copy_from_user failed\n", + __func__); + mutex_unlock(&cd->lock); + return -EFAULT; + } + ret = compdev_post_buffer_locked(cd, &img); + + break; + case COMPDEV_POST_SCENE_INFO_IOC: + memset(&s_info, 0, sizeof(s_info)); + /* Get the user data */ + if (copy_from_user(&s_info, (void *)arg, sizeof(s_info))) { + dev_warn(cd->dev, + "%s: copy_from_user failed\n", + __func__); + mutex_unlock(&cd->lock); + return -EFAULT; + } + ret = compdev_post_scene_info_locked(cd, &s_info); + + 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, const char *name) +{ + mutex_init(&cd->lock); + INIT_LIST_HEAD(&cd->list); + init_completion(&cd->fence); + + cd->mdev.minor = MISC_DYNAMIC_MINOR; + cd->mdev.name = name; + cd->mdev.fops = &compdev_fops; + cd->dev = cd->mdev.this_device; +} + +static void init_dss_context(struct dss_context *dss_ctx, + struct mcde_display_device *ddev, struct compdev *cd) +{ + dss_ctx->ddev = ddev; + dss_ctx->dev = cd->dev; + memset(&dss_ctx->cache_ctx, 0, sizeof(struct buffer_cache_context)); + dss_ctx->cache_ctx.dev = dss_ctx->dev; +} + +int compdev_create(struct mcde_display_device *ddev, + struct mcde_overlay *parent_ovly, bool mcde_rotation) +{ + int ret = 0; + int i; + struct compdev *cd; + struct mcde_video_mode vmode; + struct mcde_overlay_info info; + + char name[10]; + + if (dev_counter == 0) { + for (i = 0; i < MAX_NBR_OF_COMPDEVS; i++) + compdevs[i] = NULL; + } + + if (dev_counter > MAX_NBR_OF_COMPDEVS) + return -ENOMEM; + + cd = kzalloc(sizeof(struct compdev), GFP_KERNEL); + if (!cd) + return -ENOMEM; + + compdevs[dev_counter] = cd; + cd->dev_index = dev_counter; + + snprintf(name, sizeof(name), "%s%d", COMPDEV_DEFAULT_DEVICE_PREFIX, + dev_counter++); + init_compdev(cd, name); + + init_dss_context(&cd->dss_ctx, ddev, cd); + + mcde_dss_get_video_mode(ddev, &vmode); + + cd->worker_thread = create_workqueue(name); + if (!cd->worker_thread) { + ret = -ENOMEM; + goto fail_workqueue; + } + + cd->dss_ctx.ovly[0] = parent_ovly; + if (!cd->dss_ctx.ovly[0]) { + ret = -ENOMEM; + goto fail_create_ovly; + } + + for (i = 1; i < NUM_COMPDEV_BUFS; i++) { + cd->dss_ctx.ovly[i] = mcde_dss_create_overlay(ddev, &info); + if (!cd->dss_ctx.ovly[i]) { + ret = -ENOMEM; + goto fail_create_ovly; + } + if (mcde_dss_enable_overlay(cd->dss_ctx.ovly[i])) + goto fail_create_ovly; + if (disable_overlay(cd->dss_ctx.ovly[i])) + goto fail_create_ovly; + } + + mcde_dss_get_native_resolution(ddev, &cd->dss_ctx.phy_size.width, + &cd->dss_ctx.phy_size.height); + cd->dss_ctx.display_rotation = mcde_dss_get_rotation(ddev); + cd->dss_ctx.current_buffer_rotation = 0; + + cd->mcde_rotation = mcde_rotation; + + 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->dss_ctx.ovly[i]) + mcde_dss_destroy_overlay(cd->dss_ctx.ovly[i]); + } +fail_workqueue: + kfree(cd); +out: + return ret; +} + + +int compdev_get(int dev_idx, struct compdev **cd_pp) +{ + struct compdev *cd; + cd = NULL; + + if (dev_idx >= MAX_NBR_OF_COMPDEVS) + return -ENOMEM; + + cd = compdevs[dev_idx]; + if (cd != NULL) { + mutex_lock(&cd->lock); + cd->ref_count++; + mutex_unlock(&cd->lock); + *cd_pp = cd; + return 0; + } else { + return -ENOMEM; + } +} +EXPORT_SYMBOL(compdev_get); + +int compdev_put(struct compdev *cd) +{ + int ret = 0; + if (cd == NULL) + return -ENOMEM; + + mutex_lock(&cd->lock); + cd->ref_count--; + if (cd->ref_count < 0) + dev_warn(cd->dev, + "%s: Incorrect ref count\n", __func__); + mutex_unlock(&cd->lock); + return ret; +} +EXPORT_SYMBOL(compdev_put); + +int compdev_get_size(struct compdev *cd, struct compdev_size *size) +{ + int ret = 0; + if (cd == NULL) + return -ENOMEM; + + mutex_lock(&cd->lock); + + ret = compdev_get_size_locked(&cd->dss_ctx, size); + + mutex_unlock(&cd->lock); + return ret; +} +EXPORT_SYMBOL(compdev_get_size); + +int compdev_get_listener_state(struct compdev *cd, + enum compdev_listener_state *listener_state) +{ + int ret = 0; + if (cd == NULL) + return -ENOMEM; + + mutex_lock(&cd->lock); + + ret = compdev_get_listener_state_locked(cd, listener_state); + + mutex_unlock(&cd->lock); + return ret; +} +EXPORT_SYMBOL(compdev_get_listener_state); + + +int compdev_post_buffer(struct compdev *cd, struct compdev_img *img) +{ + int ret = 0; + if (cd == NULL) + return -ENOMEM; + + mutex_lock(&cd->lock); + + ret = compdev_post_buffer_locked(cd, img); + + mutex_unlock(&cd->lock); + return ret; +} +EXPORT_SYMBOL(compdev_post_buffer); + +int compdev_post_scene_info(struct compdev *cd, + struct compdev_scene_info *s_info) +{ + int ret = 0; + if (cd == NULL) + return -ENOMEM; + + mutex_lock(&cd->lock); + + ret = compdev_post_scene_info_locked(cd, s_info); + + mutex_unlock(&cd->lock); + return ret; +} +EXPORT_SYMBOL(compdev_post_scene_info); + +int compdev_register_listener_callbacks(struct compdev *cd, void *data, + post_buffer_callback pb_cb, post_scene_info_callback si_cb) +{ + int ret = 0; + if (cd == NULL) + return -ENOMEM; + mutex_lock(&cd->lock); + cd->cb_data = data; + cd->pb_cb = pb_cb; + cd->si_cb = si_cb; + mutex_unlock(&cd->lock); + return ret; +} +EXPORT_SYMBOL(compdev_register_listener_callbacks); + +int compdev_deregister_callbacks(struct compdev *cd) +{ + int ret = 0; + if (cd == NULL) + return -ENOMEM; + mutex_lock(&cd->lock); + cd->cb_data = NULL; + cd->pb_cb = NULL; + cd->si_cb = NULL; + mutex_unlock(&cd->lock); + return ret; +} +EXPORT_SYMBOL(compdev_deregister_callbacks); + +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->dss_ctx.ddev == ddev) { + list_del(&cd->list); + misc_deregister(&cd->mdev); + for (i = 1; i < NUM_COMPDEV_BUFS; i++) + mcde_dss_destroy_overlay(cd->dss_ctx.ovly[i]); + b2r2_blt_close(cd->dss_ctx.blt_handle); + + release_prev_frame(&cd->dss_ctx); + + /* Free potential temp buffers */ + for (i = 0; i < cd->dss_ctx.temp_img_count; i++) + free_comp_img_buf(cd->dss_ctx.temp_img[i], + cd->dev); + + for (i = 0; i < BUFFER_CACHE_DEPTH; i++) { + if (cd->dss_ctx.cache_ctx.img[i]) { + free_comp_img_buf + (cd->dss_ctx.cache_ctx.img[i], + cd->dev); + cd->dss_ctx.cache_ctx.img[i] = NULL; + } + } + + destroy_workqueue(cd->worker_thread); + kfree(cd); + break; + } + } + dev_counter--; + 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->dss_ctx.ovly[i]); + + release_prev_frame(&cd->dss_ctx); + /* Free potential temp buffers */ + for (i = 0; i < cd->dss_ctx.temp_img_count; i++) + free_comp_img_buf(cd->dss_ctx.temp_img[i], cd->dev); + + for (i = 0; i < BUFFER_CACHE_DEPTH; i++) { + if (cd->dss_ctx.cache_ctx.img[i]) { + free_comp_img_buf + (cd->dss_ctx.cache_ctx.img[i], + cd->dev); + cd->dss_ctx.cache_ctx.img[i] = NULL; + } + } + + 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..5413a252d35 --- /dev/null +++ b/drivers/misc/dispdev/dispdev.c @@ -0,0 +1,659 @@ +/* + * 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; + char name[sizeof(DISPDEV_DEFAULT_DEVICE_PREFIX) + 3]; +}; + +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; + + dd = kzalloc(sizeof(struct dispdev), GFP_KERNEL); + if (!dd) + return -ENOMEM; + + snprintf(dd->name, sizeof(dd->name), "%s%d", + DISPDEV_DEFAULT_DEVICE_PREFIX, counter++); + init_dispdev(dd, ddev, dd->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 a290be51a1f..93a7c86171e 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) @@ -2415,6 +2417,8 @@ source "drivers/video/omap/Kconfig" source "drivers/video/omap2/Kconfig" source "drivers/video/exynos/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 9356add945b..3a4ad2ebe33 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -139,6 +139,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..f271f4e7ea1 --- /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_api.o 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 b2r2_hw_convert.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_api.c b/drivers/video/b2r2/b2r2_api.c new file mode 100644 index 00000000000..0361e85ebf3 --- /dev/null +++ b/drivers/video/b2r2/b2r2_api.c @@ -0,0 +1,1643 @@ +/* + * Copyright (C) ST-Ericsson SA 2010/2012 + * + * ST-Ericsson B2R2 Blitter module API + * + * Author: Jorgen Nilsson <jorgen.nilsson@stericsson.com> + * 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 <linux/kref.h> + +#include "b2r2_internal.h" +#include "b2r2_control.h" +#include "b2r2_core.h" +#include "b2r2_timing.h" +#include "b2r2_utils.h" +#include "b2r2_debug.h" +#include "b2r2_input_validation.h" +#include "b2r2_profiler_socket.h" +#include "b2r2_hw.h" + +/* + * 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. + */ + +#define DATAS_START_SIZE 10 +#define DATAS_GROW_SIZE 5 + +/** + * @miscdev: The miscdev presenting b2r2 to the system + */ +struct b2r2_blt { + spinlock_t lock; + int next_job_id; + struct miscdevice miscdev; + struct device *dev; + struct mutex datas_lock; + /** + * datas - Stores the b2r2_blt_data mapped to the cliend handle + */ + struct b2r2_blt_data **datas; + /** + * data_count - The current maximum of active datas + */ + int data_count; +}; + +struct b2r2_blt_data { + struct b2r2_control_instance *ctl_instace[B2R2_MAX_NBR_DEVICES]; +}; + +/** + * Used to keep track of coming and going b2r2 cores and + * the number of active instance references + */ +struct b2r2_control_ref { + struct b2r2_control *b2r2_control; + spinlock_t lock; +}; + +/** + * b2r2_blt - The blitter device, /dev/b2r2_blt + */ +struct kref blt_refcount; +static struct b2r2_blt *b2r2_blt; + +/** + * b2r2_control - The core controls and synchronization mechanism + */ +static struct b2r2_control_ref b2r2_controls[B2R2_MAX_NBR_DEVICES]; + +/** + * b2r2_blt_add_control - Add the b2r2 core control + */ +void b2r2_blt_add_control(struct b2r2_control *cont) +{ + unsigned long flags; + BUG_ON(cont->id < 0 || cont->id >= B2R2_MAX_NBR_DEVICES); + + spin_lock_irqsave(&b2r2_controls[cont->id].lock, flags); + if (b2r2_controls[cont->id].b2r2_control == NULL) + b2r2_controls[cont->id].b2r2_control = cont; + spin_unlock_irqrestore(&b2r2_controls[cont->id].lock, flags); +} + +/** + * b2r2_blt_remove_control - Remove the b2r2 core control + */ +void b2r2_blt_remove_control(struct b2r2_control *cont) +{ + unsigned long flags; + BUG_ON(cont->id < 0 || cont->id >= B2R2_MAX_NBR_DEVICES); + + spin_lock_irqsave(&b2r2_controls[cont->id].lock, flags); + b2r2_controls[cont->id].b2r2_control = NULL; + spin_unlock_irqrestore(&b2r2_controls[cont->id].lock, flags); +} + +/** + * b2r2_blt_get_control - Lock control for writing/removal + */ +static struct b2r2_control *b2r2_blt_get_control(int i) +{ + struct b2r2_control *cont; + unsigned long flags; + BUG_ON(i < 0 || i >= B2R2_MAX_NBR_DEVICES); + + spin_lock_irqsave(&b2r2_controls[i].lock, flags); + cont = (struct b2r2_control *) b2r2_controls[i].b2r2_control; + if (cont != NULL) { + if (!cont->enabled) + cont = NULL; + else + kref_get(&cont->ref); + } + spin_unlock_irqrestore(&b2r2_controls[i].lock, flags); + + return cont; +} + +/** + * b2r2_blt_release_control - Unlock control for writing/removal + */ +static void b2r2_blt_release_control(int i) +{ + struct b2r2_control *cont; + unsigned long flags; + BUG_ON(i < 0 || i >= B2R2_MAX_NBR_DEVICES); + + spin_lock_irqsave(&b2r2_controls[i].lock, flags); + cont = (struct b2r2_control *) b2r2_controls[i].b2r2_control; + spin_unlock_irqrestore(&b2r2_controls[i].lock, flags); + if (cont != NULL) + kref_put(&cont->ref, b2r2_core_release); +} + +/** + * Increase size of array containing b2r2 handles + */ +static int grow_datas(void) +{ + struct b2r2_blt_data **new_datas = NULL; + int new_data_count = b2r2_blt->data_count + DATAS_GROW_SIZE; + int ret = 0; + + new_datas = kzalloc(new_data_count * sizeof(*new_datas), GFP_KERNEL); + if (new_datas == NULL) { + ret = -ENOMEM; + goto exit; + } + + memcpy(new_datas, b2r2_blt->datas, + b2r2_blt->data_count * sizeof(*b2r2_blt->datas)); + + kfree(b2r2_blt->datas); + + b2r2_blt->data_count = new_data_count; + b2r2_blt->datas = new_datas; +exit: + return ret; +} + +/** + * Allocate and/or reserve a b2r2 handle + */ +static int alloc_handle(struct b2r2_blt_data *blt_data) +{ + int handle; + int ret; + + mutex_lock(&b2r2_blt->datas_lock); + + if (b2r2_blt->datas == NULL) { + b2r2_blt->datas = kzalloc( + DATAS_START_SIZE * sizeof(*b2r2_blt->datas), + GFP_KERNEL); + if (b2r2_blt->datas == NULL) { + ret = -ENOMEM; + goto exit; + } + b2r2_blt->data_count = DATAS_START_SIZE; + } + + for (handle = 0; handle < b2r2_blt->data_count; handle++) { + if (b2r2_blt->datas[handle] == NULL) { + b2r2_blt->datas[handle] = blt_data; + break; + } + + if (handle == b2r2_blt->data_count - 1) { + ret = grow_datas(); + if (ret < 0) + goto exit; + } + } + ret = handle; +exit: + mutex_unlock(&b2r2_blt->datas_lock); + + return ret; +} + +/** + * Get b2r2 data from b2r2 handle + */ +static struct b2r2_blt_data *get_data(int handle) +{ + if (handle >= b2r2_blt->data_count || handle < 0) + return NULL; + else + return b2r2_blt->datas[handle]; +} + +/** + * Unreserve b2r2 handle + */ +static void free_handle(int handle) +{ + if (handle < b2r2_blt->data_count && handle >= 0) + b2r2_blt->datas[handle] = NULL; +} + +/** + * Get the next job number. This is the one returned to the client + * if the blit request was successful. + */ +static int get_next_job_id(void) +{ + int job_id; + unsigned long flags; + + spin_lock_irqsave(&b2r2_blt->lock, flags); + if (b2r2_blt->next_job_id < 1) + b2r2_blt->next_job_id = 1; + job_id = b2r2_blt->next_job_id++; + spin_unlock_irqrestore(&b2r2_blt->lock, flags); + + return job_id; +} + +/** + * Limit the number of cores used in some "easy" and impossible cases + */ +static int limit_blits(int n_split, struct b2r2_blt_req *user_req) +{ + if (n_split <= 1) + return n_split; + + if (user_req->dst_rect.width < 24 && user_req->dst_rect.height < 24) + return 1; + + if (user_req->src_rect.width < n_split && + user_req->src_rect.height < n_split) + return 1; + + return n_split; +} + +/** + * Check if the format inherently requires the b2r2 scaling engine to be active + */ +static bool is_scaling_fmt(enum b2r2_blt_fmt fmt) +{ + /* Plane separated formats must be treated as scaling */ + 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 true; + default: + return false; + } +} + +/** + * Check for macroblock formats + */ +static bool 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; + } +} + +/** + * Split a request rectangle on available cores + */ +static int b2r2_blt_split_request(struct b2r2_blt_data *blt_data, + struct b2r2_blt_req *user_req, + struct b2r2_blt_request **split_requests, + struct b2r2_control_instance **ctl, + int *n_split) +{ + int sstep_x, sstep_y, dstep_x, dstep_y; + int dstart_x, dstart_y; + int bstart_x, bstart_y; + int dpos_x, dpos_y; + int bpos_x, bpos_y; + int dso_x = 1; + int dso_y = 1; + int sf_x, sf_y; + int i; + int srw, srh; + int drw, drh; + bool ssplit_x = true; + bool dsplit_x = true; + enum b2r2_blt_transform transform; + bool is_rotation = false; + bool is_scaling = false; + bool bg_blend = false; + u32 core_mask = 0; + + srw = user_req->src_rect.width; + srh = user_req->src_rect.height; + drw = user_req->dst_rect.width; + drh = user_req->dst_rect.height; + transform = user_req->transform; + + /* Early exit in the basic cases */ + if (*n_split == 0) { + return -ENOSYS; + } else if (*n_split == 1 || + (srw < *n_split && srh < *n_split) || + (drw < *n_split && drh < *n_split) || + is_mb_fmt(user_req->src_img.fmt)) { + /* Handle macroblock formats with one + * core for now since there seems to be some bug + * related to macroblock access patterns + */ + memcpy(&split_requests[0]->user_req, + user_req, + sizeof(*user_req)); + split_requests[0]->core_mask = 1; + *n_split = 1; + return 0; + } + + /* + * TODO: fix the load balancing algorithm + */ + + is_rotation = (transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) != 0; + + /* Check for scaling */ + if (is_rotation) { + is_scaling = (user_req->src_rect.width != + user_req->dst_rect.height) || + (user_req->src_rect.height != + user_req->dst_rect.width); + } else { + is_scaling = (user_req->src_rect.width != + user_req->dst_rect.width) || + (user_req->src_rect.height != + user_req->dst_rect.height); + } + + is_scaling = is_scaling || + is_scaling_fmt(user_req->src_img.fmt) || + is_scaling_fmt(user_req->dst_img.fmt); + + bg_blend = ((user_req->flags & B2R2_BLT_FLAG_BG_BLEND) != 0); + + /* + * Split the request + */ + + b2r2_log_info(b2r2_blt->dev, "%s: In (t:0x%08X, f:0x%08X):\n" + "\tsrc_rect x:%d, y:%d, w:%d, h:%d src fmt:0x%x\n" + "\tdst_rect x:%d, y:%d, w:%d, h:%d dst fmt:0x%x\n", + __func__, + user_req->transform, + user_req->flags, + user_req->src_rect.x, + user_req->src_rect.y, + user_req->src_rect.width, + user_req->src_rect.height, + user_req->src_img.fmt, + user_req->dst_rect.x, + user_req->dst_rect.y, + user_req->dst_rect.width, + user_req->dst_rect.height, + user_req->dst_img.fmt); + + /* TODO: We need sub pixel precision here, + * or a better way to split rects */ + dstart_x = user_req->dst_rect.x; + dstart_y = user_req->dst_rect.y; + if (bg_blend) { + bstart_x = user_req->bg_rect.x; + bstart_y = user_req->bg_rect.y; + } + + if (srw && srh) { + if ((srw < srh) && !is_scaling) { + ssplit_x = false; + sstep_y = srh / *n_split; + /* Round up */ + if (srh % (*n_split)) + sstep_y++; + + if (srh > 16) + sstep_y = ((sstep_y + 16) >> 4) << 4; + + if (transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) { + sf_y = (drw << 10) / srh; + dstep_x = (sf_y * sstep_y) >> 10; + } else { + dsplit_x = false; + sf_y = (drh << 10) / srh; + dstep_y = (sf_y * sstep_y) >> 10; + } + } else { + sstep_x = srw / *n_split; + /* Round up */ + if (srw % (*n_split)) + sstep_x++; + + if (is_scaling) { + int scale_step_size = + B2R2_RESCALE_MAX_WIDTH - 1; + int pad = (scale_step_size - + (sstep_x % scale_step_size)); + if ((sstep_x + pad) < srw) + sstep_x += pad; + } else { + /* Aim for even 16px multiples */ + if ((sstep_x & 0xF) && ((sstep_x + 16) < srw)) + sstep_x = ((sstep_x + 16) >> 4) << 4; + } + + if (transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) { + dsplit_x = false; + sf_x = (drh << 10) / srw; + dstep_y = (sf_x * sstep_x) >> 10; + } else { + sf_x = (drw << 10) / srw; + dstep_x = (sf_x * sstep_x) >> 10; + } + } + + } else { + sstep_x = sstep_y = 0; + + if (drw < drh) { + dsplit_x = false; + dstep_y = drh / *n_split; + /* Round up */ + if (drh % *n_split) + dstep_y++; + + /* Aim for even 16px multiples */ + if ((dstep_y & 0xF) && ((dstep_y + 16) < drh)) + dstep_y = ((dstep_y + 16) >> 4) << 4; + } else { + dstep_x = drw / *n_split; + /* Round up */ + if (drw % *n_split) + dstep_x++; + + /* Aim for even 16px multiples */ + if ((dstep_x & 0xF) && ((dstep_x + 16) < drw)) + dstep_x = ((dstep_x + 16) >> 4) << 4; + } + } + + /* Check for flip and rotate to establish destination + * step order */ + if (transform & B2R2_BLT_TRANSFORM_FLIP_H) { + dstart_x += drw; + if (bg_blend) + bstart_x += drw; + dso_x = -1; + } + if ((transform & B2R2_BLT_TRANSFORM_FLIP_V) || + (transform & B2R2_BLT_TRANSFORM_CCW_ROT_90)) { + dstart_y += drh; + if (bg_blend) + bstart_y += drh; + dso_y = -1; + } + + /* Set scan starting position */ + dpos_x = dstart_x; + dpos_y = dstart_y; + if (bg_blend) { + bpos_x = bstart_x; + bpos_y = bstart_y; + } + + for (i = 0; i < *n_split; i++) { + struct b2r2_blt_req *sreq = + &split_requests[i]->user_req; + + /* First mimic all */ + memcpy(sreq, user_req, sizeof(*user_req)); + + /* Then change the rects */ + if (srw && srh) { + if (ssplit_x) { + if (sstep_x > 0) { + sreq->src_rect.width = + min(sstep_x, srw); + sreq->src_rect.x += i*sstep_x; + srw -= sstep_x; + } else { + sreq->src_rect.width = srw; + } + } else { + if (sstep_y > 0) { + sreq->src_rect.y += i*sstep_y; + sreq->src_rect.height = + min(sstep_y, srh); + srh -= sstep_y; + } else { + sreq->src_rect.height = srh; + } + } + } + + if (dsplit_x) { + int sx = min(dstep_x, drw); + if (dso_x < 0) { + dpos_x += dso_x * sx; + if (bg_blend) + bpos_x += dso_x * sx; + } + sreq->dst_rect.width = sx; + sreq->dst_rect.x = dpos_x; + if (bg_blend) { + sreq->bg_rect.width = sx; + sreq->bg_rect.x = bpos_x; + } + if (dso_x > 0) { + dpos_x += dso_x * sx; + if (bg_blend) + bpos_x += dso_x * sx; + } + drw -= sx; + } else { + int sy = min(dstep_y, drh); + if (dso_y < 0) { + dpos_y += dso_y * sy; + if (bg_blend) + bpos_y += dso_y * sy; + } + sreq->dst_rect.height = sy; + sreq->dst_rect.y = dpos_y; + if (bg_blend) { + sreq->bg_rect.height = sy; + sreq->bg_rect.y = bpos_y; + } + if (dso_y > 0) { + dpos_y += dso_y * sy; + if (bg_blend) + bpos_y += dso_y * sy; + } + drh -= sy; + } + + b2r2_log_info(b2r2_blt->dev, "%s: Out:\n" + "\tsrc_rect x:%d, y:%d, w:%d, h:%d\n" + "\tdst_rect x:%d, y:%d, w:%d, h:%d\n" + "\tbg_rect x:%d, y:%d, w:%d, h:%d\n", + __func__, + sreq->src_rect.x, + sreq->src_rect.y, + sreq->src_rect.width, + sreq->src_rect.height, + sreq->dst_rect.x, + sreq->dst_rect.y, + sreq->dst_rect.width, + sreq->dst_rect.height, + sreq->bg_rect.x, + sreq->bg_rect.y, + sreq->bg_rect.width, + sreq->bg_rect.height); + + core_mask |= (1 << i); + } + + for (i = 0; i < *n_split; i++) + split_requests[i]->core_mask = core_mask; + + return 0; +} + +/** + * Get available b2r2 control instances. It will be limited + * to the number of cores available at the current point in time. + * It will also cause the cores to stay active during the time until + * release_control_instances is called. + */ +static void get_control_instances(struct b2r2_blt_data *blt_data, + struct b2r2_control_instance **ctl, int max_size, + int *count) +{ + int i; + + *count = 0; + for (i = 0; i < max_size; i++) { + struct b2r2_control_instance *ci = blt_data->ctl_instace[i]; + if (ci) { + struct b2r2_control *cont = + b2r2_blt_get_control(ci->control_id); + if (cont) { + ctl[*count] = ci; + *count += 1; + } + } + } +} + +/** + * Release b2r2 control instances. The cores allocated for the request + * are given back. + */ +static void release_control_instances(struct b2r2_control_instance **ctl, + int count) +{ + int i; + + /* Release the handles to the core controls */ + for (i = 0; i < count; i++) { + if (ctl[i]) + b2r2_blt_release_control(ctl[i]->control_id); + } +} + +/** + * Free b2r2 request + */ +static void b2r2_free_request(struct b2r2_blt_request *request) +{ + if (request) { + /* Free requests in split_requests */ + if (request->clut) + dma_free_coherent(b2r2_blt->dev, + CLUT_SIZE, + request->clut, + request->clut_phys_addr); + request->clut = NULL; + request->clut_phys_addr = 0; + kfree(request); + } +} + +/** + * Allocate internal b2r2 request based on user input. + */ +static int b2r2_alloc_request(struct b2r2_blt_req *user_req, + bool us_req, struct b2r2_blt_request **request_out) +{ + int ret = 0; + struct b2r2_blt_request *request = + kzalloc(sizeof(*request), GFP_KERNEL); + if (!request) + return -ENOMEM; + + /* Initialize the structure */ + INIT_LIST_HEAD(&request->list); + + /* + * If the user specified a color look-up table, + * make a copy that the HW can use. + */ + if ((user_req->flags & + B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) != 0) { + request->clut = dma_alloc_coherent( + b2r2_blt->dev, + CLUT_SIZE, + &(request->clut_phys_addr), + GFP_DMA | GFP_KERNEL); + if (request->clut == NULL) { + b2r2_log_err(b2r2_blt->dev, + "%s CLUT allocation " + "failed.\n", __func__); + ret = -ENOMEM; + goto exit; + } + + if (us_req) { + if (copy_from_user(request->clut, + user_req->clut, CLUT_SIZE)) { + b2r2_log_err(b2r2_blt->dev, "%s: CLUT " + "copy_from_user failed\n", + __func__); + ret = -EFAULT; + goto exit; + } + } else { + memcpy(request->clut, user_req->clut, + CLUT_SIZE); + } + } + + request->profile = is_profiler_registered_approx(); + + *request_out = request; +exit: + if (ret != 0) + b2r2_free_request(request); + + return ret; +} + +/** + * Do the blit job split on available cores. + */ +static int b2r2_blt_blit_internal(int handle, + struct b2r2_blt_req *user_req, + bool us_req) +{ + int request_id; + int i; + int n_instance = 0; + int n_blit = 0; + int ret = 0; + struct b2r2_blt_data *blt_data; + struct b2r2_blt_req ureq; + + /* The requests and the designated workers */ + struct b2r2_blt_request *split_requests[B2R2_MAX_NBR_DEVICES]; + struct b2r2_control_instance *ctl[B2R2_MAX_NBR_DEVICES]; + + blt_data = get_data(handle); + if (blt_data == NULL) { + b2r2_log_warn(b2r2_blt->dev, + "%s, blitter instance not found (handle=%d)\n", + __func__, handle); + return -ENOSYS; + } + + /* Get the b2r2 core controls for the job */ + get_control_instances(blt_data, ctl, B2R2_MAX_NBR_DEVICES, &n_instance); + if (n_instance == 0) { + b2r2_log_err(b2r2_blt->dev, "%s: No b2r2 cores available.\n", + __func__); + return -ENOSYS; + } + + /* Get the user data */ + if (us_req) { + if (copy_from_user(&ureq, user_req, sizeof(ureq))) { + b2r2_log_err(b2r2_blt->dev, + "%s: copy_from_user failed\n", + __func__); + ret = -EFAULT; + goto exit; + } + } else { + memcpy(&ureq, user_req, sizeof(ureq)); + } + + /* + * B2R2 cannot handle destination clipping on buffers + * allocated close to 64MiB bank boundaries. + * recalculate src_ and dst_rect to avoid clipping. + * + * Also this is needed to ensure the request split + * operates on visible areas + */ + b2r2_recalculate_rects(b2r2_blt->dev, &ureq); + + if (!b2r2_validate_user_req(b2r2_blt->dev, &ureq)) { + b2r2_log_warn(b2r2_blt->dev, + "%s: b2r2_validate_user_req failed.\n", + __func__); + ret = -EINVAL; + goto exit; + } + + /* Don't split small requests */ + n_blit = limit_blits(n_instance, &ureq); + + /* The id needs to be universal on + * all cores */ + request_id = get_next_job_id(); + +#ifdef CONFIG_B2R2_GENERIC_ONLY + /* Limit the generic only solution to one core (for now) */ + n_blit = 1; +#endif + + for (i = 0; i < n_blit; i++) { + ret = b2r2_alloc_request(&ureq, us_req, &split_requests[i]); + if (ret < 0 || !split_requests[i]) { + b2r2_log_err(b2r2_blt->dev, "%s: Failed to alloc mem\n", + __func__); + ret = -ENOMEM; + break; + } + split_requests[i]->instance = ctl[i]; + split_requests[i]->job.job_id = request_id; + split_requests[i]->job.data = (int) ctl[i]->control->data; + } + + /* Split the request */ + if (ret >= 0) + ret = b2r2_blt_split_request(blt_data, &ureq, + &split_requests[0], &ctl[0], &n_blit); + + /* If anything failed, clean up allocated memory */ + if (ret < 0) { + for (i = 0; i < n_blit; i++) + b2r2_free_request(split_requests[i]); + b2r2_log_err(b2r2_blt->dev, + "%s: b2r2_blt_split_request failed.\n", + __func__); + goto exit; + } + +#ifdef CONFIG_B2R2_GENERIC_ONLY + if (ureq.flags & B2R2_BLT_FLAG_BG_BLEND) { + /* No support for BG BLEND in generic + * implementation yet */ + b2r2_log_warn(b2r2_blt->dev, "%s: Unsupported: " + "Background blend in b2r2_generic_blt\n", + __func__); + ret = -ENOSYS; + b2r2_free_request(split_requests[0]); + goto exit; + } + /* Use the generic path for all operations */ + ret = b2r2_generic_blt(split_requests[0]); +#else + /* Call each blitter control */ + for (i = 0; i < n_blit; i++) { + ret = b2r2_control_blt(split_requests[i]); + if (ret < 0) { + b2r2_log_warn(b2r2_blt->dev, + "%s: b2r2_control_blt failed.\n", __func__); + break; + } + } + if (ret != -ENOSYS) { + int j; + /* TODO: if one blitter fails then cancel the jobs added */ + + /* Call waitjob for successful jobs + * (synchs if specified in request) */ + if (ureq.flags & B2R2_BLT_FLAG_DRY_RUN) + goto exit; + + for (j = 0; j < i; j++) { + int rtmp; + + rtmp = b2r2_control_waitjob(split_requests[j]); + if (rtmp < 0) { + b2r2_log_err(b2r2_blt->dev, + "%s: b2r2_control_waitjob failed.\n", + __func__); + } + + /* Save just the one error */ + ret = (ret >= 0) ? rtmp : ret; + } + } +#endif +#ifdef CONFIG_B2R2_GENERIC_FALLBACK + if (ret == -ENOSYS) { + struct b2r2_blt_request *request_gen = NULL; + if (ureq.flags & B2R2_BLT_FLAG_BG_BLEND) { + /* No support for BG BLEND in generic + * implementation yet */ + b2r2_log_warn(b2r2_blt->dev, "%s: Unsupported: " + "Background blend in b2r2_generic_blt\n", + __func__); + goto exit; + } + + b2r2_log_info(b2r2_blt->dev, + "b2r2_blt=%d Going generic.\n", ret); + ret = b2r2_alloc_request(&ureq, us_req, &request_gen); + if (ret < 0 || !request_gen) { + b2r2_log_err(b2r2_blt->dev, + "%s: Failed to alloc mem for " + "request_gen\n", __func__); + ret = -ENOMEM; + goto exit; + } + + /* Initialize the structure */ + request_gen->instance = ctl[0]; + memcpy(&request_gen->user_req, &ureq, + sizeof(request_gen->user_req)); + request_gen->core_mask = 1; + request_gen->job.job_id = request_id; + request_gen->job.data = (int) ctl[0]->control->data; + + ret = b2r2_generic_blt(request_gen); + b2r2_log_info(b2r2_blt->dev, "\nb2r2_generic_blt=%d " + "Generic done.\n", ret); + } +#endif +exit: + release_control_instances(ctl, n_instance); + + ret = ret >= 0 ? request_id : ret; + + return ret; +} + +/** + * Free the memory used for the b2r2_blt device + */ +static void b2r2_blt_release(struct kref *ref) +{ + BUG_ON(b2r2_blt == NULL); + if (b2r2_blt == NULL) + return; + kfree(b2r2_blt->datas); + kfree(b2r2_blt); + b2r2_blt = NULL; +} + +int b2r2_blt_open(void) +{ + int ret = 0; + struct b2r2_blt_data *blt_data = NULL; + int i; + + if (!atomic_inc_not_zero(&blt_refcount.refcount)) + return -ENOSYS; + + /* Allocate blitter instance data structure */ + blt_data = (struct b2r2_blt_data *) + kzalloc(sizeof(*blt_data), GFP_KERNEL); + if (!blt_data) { + b2r2_log_err(b2r2_blt->dev, "%s: Failed to alloc\n", __func__); + ret = -ENOMEM; + goto err; + } + + for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++) { + struct b2r2_control *control = b2r2_blt_get_control(i); + if (control != NULL) { + struct b2r2_control_instance *ci; + + /* Allocate and initialize the control instance */ + ci = kzalloc(sizeof(*ci), GFP_KERNEL); + if (!ci) { + b2r2_log_err(b2r2_blt->dev, + "%s: Failed to alloc\n", + __func__); + ret = -ENOMEM; + b2r2_blt_release_control(i); + goto err; + } + ci->control_id = i; + ci->control = control; + ret = b2r2_control_open(ci); + if (ret < 0) { + b2r2_log_err(b2r2_blt->dev, + "%s: Failed to open b2r2 control %d\n", + __func__, i); + kfree(ci); + b2r2_blt_release_control(i); + goto err; + } + blt_data->ctl_instace[i] = ci; + b2r2_blt_release_control(i); + } else { + blt_data->ctl_instace[i] = NULL; + } + } + + /* TODO: Create kernel worker kthread */ + + ret = alloc_handle(blt_data); + if (ret < 0) + goto err; + + kref_put(&blt_refcount, b2r2_blt_release); + + return ret; + +err: + /* Destroy the blitter instance data structure */ + if (blt_data) { + for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++) + kfree(blt_data->ctl_instace[i]); + kfree(blt_data); + } + + kref_put(&blt_refcount, b2r2_blt_release); + + return ret; +} +EXPORT_SYMBOL(b2r2_blt_open); + +int b2r2_blt_close(int handle) +{ + int i; + struct b2r2_blt_data *blt_data; + int ret = 0; + + if (!atomic_inc_not_zero(&blt_refcount.refcount)) + return -ENOSYS; + + b2r2_log_info(b2r2_blt->dev, "%s\n", __func__); + + blt_data = get_data(handle); + if (blt_data == NULL) { + b2r2_log_warn(b2r2_blt->dev, + "%s, blitter data not found (handle=%d)\n", + __func__, handle); + ret = -ENOSYS; + goto exit; + } + free_handle(handle); + + for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++) { + struct b2r2_control_instance *ci = + blt_data->ctl_instace[i]; + if (ci != NULL) { + struct b2r2_control *cont = + b2r2_blt_get_control(ci->control_id); + if (cont) { + /* Release the instance */ + b2r2_control_release(ci); + b2r2_blt_release_control(ci->control_id); + } + kfree(ci); + } + } + kfree(blt_data); + +exit: + kref_put(&blt_refcount, b2r2_blt_release); + + return ret; +} +EXPORT_SYMBOL(b2r2_blt_close); + +int b2r2_blt_request(int handle, + struct b2r2_blt_req *user_req) +{ + int ret = 0; + + if (!atomic_inc_not_zero(&blt_refcount.refcount)) + return -ENOSYS; + + /* Exclude some currently unsupported cases */ + if ((user_req->flags & B2R2_BLT_FLAG_REPORT_WHEN_DONE) || + (user_req->flags & B2R2_BLT_FLAG_REPORT_PERFORMANCE) || + (user_req->report1 != 0)) { + b2r2_log_err(b2r2_blt->dev, + "%s No callback support in the kernel API\n", + __func__); + ret = -ENOSYS; + goto exit; + } + + ret = b2r2_blt_blit_internal(handle, user_req, false); + +exit: + kref_put(&blt_refcount, b2r2_blt_release); + + return ret; +} +EXPORT_SYMBOL(b2r2_blt_request); + +int b2r2_blt_synch(int handle, int request_id) +{ + int ret = 0; + int i; + int n_synch = 0; + struct b2r2_control_instance *ctl[B2R2_MAX_NBR_DEVICES]; + struct b2r2_blt_data *blt_data; + + if (!atomic_inc_not_zero(&blt_refcount.refcount)) + return -ENOSYS; + + b2r2_log_info(b2r2_blt->dev, "%s\n", __func__); + + blt_data = get_data(handle); + if (blt_data == NULL) { + b2r2_log_warn(b2r2_blt->dev, + "%s, blitter data not found (handle=%d)\n", + __func__, handle); + ret = -ENOSYS; + goto exit; + } + + /* Get the b2r2 core controls for the job */ + get_control_instances(blt_data, ctl, B2R2_MAX_NBR_DEVICES, &n_synch); + if (n_synch == 0) { + b2r2_log_err(b2r2_blt->dev, "%s: No b2r2 cores available.\n", + __func__); + ret = -ENOSYS; + goto exit; + } + + for (i = 0; i < n_synch; i++) { + ret = b2r2_control_synch(ctl[i], request_id); + if (ret != 0) { + b2r2_log_err(b2r2_blt->dev, + "%s: b2r2_control_synch failed.\n", + __func__); + break; + } + } + + /* Release the handles to the core controls */ + release_control_instances(ctl, n_synch); + +exit: + kref_put(&blt_refcount, b2r2_blt_release); + + b2r2_log_info(b2r2_blt->dev, + "%s, request_id=%d, returns %d\n", __func__, request_id, ret); + + return ret; +} +EXPORT_SYMBOL(b2r2_blt_synch); + +/** + * The user space API + */ + +/** + * b2r2_blt_open_us - Implements file open on the b2r2_blt device + * + * @inode: File system inode + * @filp: File pointer + * + * A b2r2_blt_data handle is created and stored in the file structure. + */ +static int b2r2_blt_open_us(struct inode *inode, struct file *filp) +{ + int ret = 0; + int handle; + + handle = b2r2_blt_open(); + if (handle < 0) { + b2r2_log_err(b2r2_blt->dev, "%s: Failed to open handle\n", + __func__); + ret = handle; + goto exit; + } + filp->private_data = (void *) handle; +exit: + return ret; +} + +/** + * b2r2_blt_release_us - 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_us(struct inode *inode, struct file *filp) +{ + int ret; + ret = b2r2_blt_close((int) filp->private_data); + return ret; +} + +/** + * Query B2R2 capabilities + * + * @blt_data: The B2R2 BLT instance + * @query_cap: The structure receiving the capabilities + */ +static int b2r2_blt_query_cap(struct b2r2_blt_data *blt_data, + struct b2r2_blt_query_cap *query_cap) +{ + /* FIXME: Not implemented yet */ + return -ENOSYS; +} + +/** + * b2r2_blt_ioctl_us - 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_us(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + int handle = (int) file->private_data; + + /** Process actual ioctl */ + b2r2_log_info(b2r2_blt->dev, "%s\n", __func__); + + /* Get the instance from the file structure */ + switch (cmd) { + case B2R2_BLT_IOC: { + /* arg is user pointer to struct b2r2_blt_request */ + ret = b2r2_blt_blit_internal(handle, + (struct b2r2_blt_req *) arg, true); + break; + } + + case B2R2_BLT_SYNCH_IOC: + /* arg is request_id */ + ret = b2r2_blt_synch(handle, (int) arg); + break; + + case B2R2_BLT_QUERY_CAP_IOC: { + /* Arg is struct b2r2_blt_query_cap */ + struct b2r2_blt_query_cap query_cap; + struct b2r2_blt_data *blt_data = get_data(handle); + + /* Get the user data */ + if (copy_from_user(&query_cap, (void *)arg, + sizeof(query_cap))) { + b2r2_log_err(b2r2_blt->dev, + "%s: copy_from_user failed\n", + __func__); + ret = -EFAULT; + goto exit; + } + + /* Fill in our capabilities */ + ret = b2r2_blt_query_cap(blt_data, &query_cap); + + /* Return data to user */ + if (copy_to_user((void *)arg, &query_cap, + sizeof(query_cap))) { + b2r2_log_err(b2r2_blt->dev, + "%s: copy_to_user failed\n", + __func__); + ret = -EFAULT; + goto exit; + } + break; + } + + default: + /* Unknown command */ + b2r2_log_err(b2r2_blt->dev, "%s: Unknown cmd %d\n", + __func__, cmd); + ret = -EINVAL; + break; + + } + +exit: + if (ret < 0) + b2r2_log_err(b2r2_blt->dev, "%s: Return with error %d!\n", + __func__, -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_us(struct file *filp, poll_table *wait) +{ + struct b2r2_blt_data *blt_data = + (struct b2r2_blt_data *) filp->private_data; + struct b2r2_control_instance *ctl[B2R2_MAX_NBR_DEVICES]; + unsigned int ret = POLLIN | POLLRDNORM; + int n_poll = 0; + int i; + + b2r2_log_info(b2r2_blt->dev, "%s\n", __func__); + + /* Get the b2r2 core controls for the job */ + get_control_instances(blt_data, ctl, B2R2_MAX_NBR_DEVICES, &n_poll); + if (n_poll == 0) { + b2r2_log_err(b2r2_blt->dev, "%s: No b2r2 cores available.\n", + __func__); + ret = -ENOSYS; + goto exit; + } + + /* Poll each core control instance */ + for (i = 0; i < n_poll && ret != 0; i++) { + poll_wait(filp, &ctl[i]->report_list_waitq, wait); + mutex_lock(&ctl[i]->lock); + if (list_empty(&ctl[i]->report_list)) + ret = 0; /* No reports */ + mutex_unlock(&ctl[i]->lock); + } + + /* Release the handles to the core controls */ + release_control_instances(ctl, n_poll); + +exit: + b2r2_log_info(b2r2_blt->dev, "%s: returns %d, n_poll: %d\n", + __func__, ret, n_poll); + + return ret; +} + +/** + * 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_us(struct file *filp, + char __user *buf, size_t count, loff_t *f_pos) +{ + int ret = 0; + int n_read = 0; + int i; + int first_index = 0; + struct b2r2_blt_report report; + struct b2r2_blt_request *requests[B2R2_MAX_NBR_DEVICES]; + struct b2r2_blt_data *blt_data = + (struct b2r2_blt_data *) filp->private_data; + struct b2r2_control_instance *ctl[B2R2_MAX_NBR_DEVICES]; + struct b2r2_control_instance *first = NULL; + bool block = ((filp->f_flags & O_NONBLOCK) == 0); + u32 core_mask = 0; + + b2r2_log_info(b2r2_blt->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; + + memset(ctl, 0, sizeof(*ctl) * B2R2_MAX_NBR_DEVICES); + /* Get the b2r2 core controls for the job */ + for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++) { + struct b2r2_control_instance *ci = blt_data->ctl_instace[i]; + if (ci) { + struct b2r2_control *cont = + b2r2_blt_get_control(ci->control_id); + if (cont) { + ctl[i] = ci; + n_read++; + } + } + } + if (n_read == 0) { + b2r2_log_err(b2r2_blt->dev, "%s: No b2r2 cores available.\n", + __func__); + return -ENOSYS; + } + + /* Find which control to ask for a report first */ + for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++) { + if (ctl[i] != NULL) { + first = ctl[i]; + first_index = i; + break; + } + } + if (!first) { + b2r2_log_err(b2r2_blt->dev, "%s: Internal error.\n", + __func__); + return -ENOSYS; + } + + memset(requests, 0, sizeof(*requests) * B2R2_MAX_NBR_DEVICES); + /* Read report from core 0 */ + ret = b2r2_control_read(first, &requests[first_index], block); + if (ret <= 0 || requests[0] == NULL) { + b2r2_log_err(b2r2_blt->dev, "%s: b2r2_control_read failed.\n", + __func__); + ret = -EFAULT; + goto exit; + } + core_mask = requests[first_index]->core_mask >> 1; + core_mask &= ~(1 << first_index); + + /* If there are any more cores, try reading the report + * with the specific ID from the other cores */ + for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++) { + if ((core_mask & 1) && (ctl[i] != NULL)) { + /* TODO: Do we need to wait here? */ + ret = b2r2_control_read_id(ctl[i], &requests[i], block, + requests[first_index]->request_id); + if (ret <= 0 || requests[i] == NULL) { + b2r2_log_err(b2r2_blt->dev, + "%s: b2r2_control_read failed.\n", + __func__); + break; + } + } + core_mask = core_mask >> 1; + } + + if (ret > 0) { + /* Construct a report and copy to userland */ + report.request_id = requests[0]->request_id; + report.report1 = requests[0]->user_req.report1; + report.report2 = requests[0]->user_req.report2; + report.usec_elapsed = 0; /* TBD */ + + if (copy_to_user(buf, &report, sizeof(report))) { + b2r2_log_err(b2r2_blt->dev, + "%s: copy_to_user failed.\n", + __func__); + ret = -EFAULT; + } + } + + if (ret > 0) { + for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++) + /* + * Release matching the addref when the job was put + * into the report list + */ + if (requests[i] != NULL) + b2r2_core_job_release(&requests[i]->job, + __func__); + } else { + /* We failed at one core or copy to user failed */ + for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++) + if (requests[i] != NULL) + list_add(&requests[i]->list, + &ctl[i]->report_list); + goto exit; + } + + ret = count; + +exit: + /* Release the handles to the core controls */ + release_control_instances(ctl, n_read); + + return ret; +} + +/** + * b2r2_blt_fops - File operations for b2r2_blt + */ +static const struct file_operations b2r2_blt_fops = { + .owner = THIS_MODULE, + .open = b2r2_blt_open_us, + .release = b2r2_blt_release_us, + .unlocked_ioctl = b2r2_blt_ioctl_us, + .poll = b2r2_blt_poll_us, + .read = b2r2_blt_read_us, +}; + + +/** + * b2r2_probe() - This routine loads the B2R2 core driver + * + * @pdev: platform device. + */ +static int b2r2_blt_probe(struct platform_device *pdev) +{ + int ret = 0; + int i; + + BUG_ON(pdev == NULL); + + dev_info(&pdev->dev, "%s start.\n", __func__); + + if (!b2r2_blt) { + b2r2_blt = kzalloc(sizeof(*b2r2_blt), GFP_KERNEL); + if (!b2r2_blt) { + dev_err(&pdev->dev, "b2r2_blt alloc failed\n"); + ret = -EINVAL; + goto error_exit; + } + + /* Init b2r2 core control reference counters */ + for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++) + spin_lock_init(&b2r2_controls[i].lock); + } + + mutex_init(&b2r2_blt->datas_lock); + spin_lock_init(&b2r2_blt->lock); + b2r2_blt->dev = &pdev->dev; + + /* Register b2r2 driver */ + b2r2_blt->miscdev.parent = b2r2_blt->dev; + b2r2_blt->miscdev.minor = MISC_DYNAMIC_MINOR; + b2r2_blt->miscdev.name = "b2r2_blt"; + b2r2_blt->miscdev.fops = &b2r2_blt_fops; + + ret = misc_register(&b2r2_blt->miscdev); + if (ret != 0) { + printk(KERN_WARNING "%s: registering misc device fails\n", + __func__); + goto error_exit; + } + + b2r2_blt->dev = b2r2_blt->miscdev.this_device; + b2r2_blt->dev->coherent_dma_mask = 0xFFFFFFFF; + + kref_init(&blt_refcount); + + dev_info(&pdev->dev, "%s done.\n", __func__); + + return ret; + +/** Recover from any error if something fails */ +error_exit: + + kfree(b2r2_blt); + + dev_info(&pdev->dev, "%s done with errors (%d).\n", __func__, ret); + + return ret; +} + +/** + * b2r2_blt_remove - This routine unloads b2r2_blt driver + * + * @pdev: platform device. + */ +static int b2r2_blt_remove(struct platform_device *pdev) +{ + BUG_ON(pdev == NULL); + dev_info(&pdev->dev, "%s started.\n", __func__); + misc_deregister(&b2r2_blt->miscdev); + kref_put(&blt_refcount, b2r2_blt_release); + return 0; +} + +/** + * b2r2_blt_suspend() - This routine puts the B2R2 blitter 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_blt_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +/** + * b2r2_blt_resume() - This routine resumes the B2R2 blitter from sustend state. + * @pdev: platform device. + * + * This routine restore back the current state of the b2r2 device resumes. + * + */ +int b2r2_blt_resume(struct platform_device *pdev) +{ + return 0; +} + +/** + * struct platform_b2r2_driver - Platform driver configuration for the + * B2R2 core driver + */ +static struct platform_driver platform_b2r2_blt_driver = { + .remove = b2r2_blt_remove, + .driver = { + .name = "b2r2_blt", + }, + .suspend = b2r2_blt_suspend, + .resume = b2r2_blt_resume, +}; + +/** + * b2r2_init() - Module init function for the B2R2 core module + */ +static int __init b2r2_blt_init(void) +{ + printk(KERN_INFO "%s\n", __func__); + return platform_driver_probe(&platform_b2r2_blt_driver, b2r2_blt_probe); +} +module_init(b2r2_blt_init); + +/** + * b2r2_exit() - Module exit function for the B2R2 core module + */ +static void __exit b2r2_blt_exit(void) +{ + printk(KERN_INFO "%s\n", __func__); + platform_driver_unregister(&platform_b2r2_blt_driver); + return; +} +module_exit(b2r2_blt_exit); + +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_blt_main.c b/drivers/video/b2r2/b2r2_blt_main.c new file mode 100644 index 00000000000..3727f742bf1 --- /dev/null +++ b/drivers/video/b2r2/b2r2_blt_main.c @@ -0,0 +1,2840 @@ +/* + * 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_control.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. + */ + +/* Local functions */ +static void inc_stat(struct b2r2_control *cont, unsigned long *stat); +static void dec_stat(struct b2r2_control *cont, unsigned long *stat); + +#ifndef CONFIG_B2R2_GENERIC_ONLY +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 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_control_instance *instance); +static bool is_synching(struct b2r2_control_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. + */ +int b2r2_control_open(struct b2r2_control_instance *instance) +{ + int ret = 0; + struct b2r2_control *cont = instance->control; + + b2r2_log_info(cont->dev, "%s\n", __func__); + inc_stat(cont, &cont->stat_n_in_open); + + INIT_LIST_HEAD(&instance->report_list); + mutex_init(&instance->lock); + init_waitqueue_head(&instance->report_list_waitq); + init_waitqueue_head(&instance->synch_done_waitq); + 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. + */ +int b2r2_control_release(struct b2r2_control_instance *instance) +{ + int ret; + 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_control_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); + + dec_stat(cont, &cont->stat_n_in_release); + + return 0; +} + +size_t b2r2_control_read(struct b2r2_control_instance *instance, + struct b2r2_blt_request **request_out, bool block) +{ + struct b2r2_blt_request *request = NULL; +#ifdef CONFIG_B2R2_DEBUG + struct b2r2_control *cont = instance->control; +#endif + + b2r2_log_info(cont->dev, "%s\n", __func__); + + /* + * 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 (!block) + 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); + + *request_out = request; + } + mutex_unlock(&instance->lock); + + if (request) + return 1; + + /* No report returned */ + return 0; +} + +size_t b2r2_control_read_id(struct b2r2_control_instance *instance, + struct b2r2_blt_request **request_out, bool block, + int request_id) +{ + struct b2r2_blt_request *request = NULL; +#ifdef CONFIG_B2R2_DEBUG + struct b2r2_control *cont = instance->control; +#endif + + b2r2_log_info(cont->dev, "%s\n", __func__); + + /* + * 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 (!block) + 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)) { + struct b2r2_blt_request *pos; + list_for_each_entry(pos, &instance->report_list, list) { + if (pos->request_id) + request = pos; + } + } + + if (request) { + /* Remove from list to avoid reading twice */ + list_del_init(&request->list); + *request_out = request; + } + mutex_unlock(&instance->lock); + + if (request) + return 1; + + /* No report returned */ + return 0; +} + +#ifndef CONFIG_B2R2_GENERIC_ONLY +/** + * b2r2_blt - Implementation of the B2R2 blit request + * + * @instance: The B2R2 BLT instance + * @request; The request to perform + */ +int b2r2_control_blt(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_instance *instance = request->instance; + 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.data = (int) cont->data; + 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); + + 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: + 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); + job_release(&request->job); + dec_stat(cont, &cont->stat_n_jobs_released); + + dec_stat(cont, &cont->stat_n_in_blt); + + return ret; +} + +int b2r2_control_waitjob(struct b2r2_blt_request *request) +{ + int ret = 0; + struct b2r2_control_instance *instance = request->instance; + struct b2r2_control *cont = instance->control; + + /* 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__); + } + + /* + * 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; +} + +/** + * Called when job is done or cancelled + * + * @job: The job + */ +static void job_callback(struct b2r2_core_job *job) +{ + struct b2r2_blt_request *request = NULL; + struct b2r2_core *core = NULL; + struct b2r2_control *cont = NULL; + + request = container_of(job, struct b2r2_blt_request, job); + core = (struct b2r2_core *) job->data; + cont = core->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? */ + /* TODO: In the case of kernel API call, feed an asynch task to the + * instance worker (kthread) instead of polling for a report */ + 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 = NULL; + struct b2r2_core *core = NULL; + struct b2r2_control *cont = NULL; + + request = container_of(job, struct b2r2_blt_request, job); + core = (struct b2r2_core *) job->data; + cont = core->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_core *core = (struct b2r2_core *) job->data; + struct b2r2_control *cont = core->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_core *core = (struct b2r2_core *) job->data; + struct b2r2_control *cont = core->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_core *core = + (struct b2r2_core *) job->data; + struct b2r2_control *cont = core->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_core *core = (struct b2r2_core *) job->data; + struct b2r2_control *cont = core->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? */ + /* TODO: In the case of kernel API call, feed an asynch task to the + * instance worker (kthread) instead of polling for a report */ + 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_core *core = + (struct b2r2_core *) job->data; + struct b2r2_control *cont = core->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_core *core = (struct b2r2_core *) job->data; + struct b2r2_control *cont = core->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 + * + * @request; The request to perform + */ +int b2r2_generic_blt(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_instance *instance = request->instance; + 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.data = (int) cont->data; + 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->job_id = request->job.job_id; + tile_job->tag = request->job.tag; + tile_job->data = request->job.data; + 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->job_id = request->job.job_id; + tile_job->tag = request->job.tag; + tile_job->data = request->job.data; + 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. + */ +int b2r2_control_synch(struct b2r2_control_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; +} + +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->dev, 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->dev, img->fmt); + u32 img_pitch = b2r2_get_img_pitch(cont->dev, 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 (%d, requires %d)" + "buffer.\n", __func__, access, required_access); + 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->dev, 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->dev, 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_control_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_control_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 +/** + * 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_control_init(struct b2r2_control *cont) +{ + int ret; + + mutex_init(&cont->stat_lock); + +#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__); + + 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 (!IS_ERR_OR_NULL(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_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 + return ret; +} + +/** + * b2r2_control_exit() - Module exit function + */ +void b2r2_control_exit(struct b2r2_control *cont) +{ + if (cont) { + b2r2_log_info(cont->dev, "%s\n", __func__); +#ifdef CONFIG_DEBUG_FS + if (!IS_ERR_OR_NULL(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_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_control.h b/drivers/video/b2r2/b2r2_control.h new file mode 100644 index 00000000000..d13d2188618 --- /dev/null +++ b/drivers/video/b2r2/b2r2_control.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) ST-Ericsson SA 2012 + * + * ST-Ericsson B2R2 internal definitions + * + * Author: Jorgen Nilsson <jorgen.nilsson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef _LINUX_DRIVERS_VIDEO_B2R2_CONTROL_H_ +#define _LINUX_DRIVERS_VIDEO_B2R2_CONTROL_H_ + +#include "b2r2_internal.h" + +int b2r2_control_init(struct b2r2_control *cont); +void b2r2_control_exit(struct b2r2_control *cont); +int b2r2_control_open(struct b2r2_control_instance *instance); +int b2r2_control_release(struct b2r2_control_instance *instance); + +int b2r2_control_blt(struct b2r2_blt_request *request); +int b2r2_generic_blt(struct b2r2_blt_request *request); +int b2r2_control_waitjob(struct b2r2_blt_request *request); +int b2r2_control_synch(struct b2r2_control_instance *instance, + int request_id); +size_t b2r2_control_read(struct b2r2_control_instance *instance, + struct b2r2_blt_request **request_out, bool block); +size_t b2r2_control_read_id(struct b2r2_control_instance *instance, + struct b2r2_blt_request **request_out, bool block, + int request_id); + +#endif diff --git a/drivers/video/b2r2/b2r2_core.c b/drivers/video/b2r2/b2r2_core.c new file mode 100644 index 00000000000..02071d5f989 --- /dev/null +++ b/drivers/video/b2r2/b2r2_core.c @@ -0,0 +1,2763 @@ +/* + * 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 <linux/kref.h> + +#include "b2r2_internal.h" +#include "b2r2_core.h" +#include "b2r2_global.h" +#include "b2r2_structures.h" +#include "b2r2_control.h" +#include "b2r2_profiler_api.h" +#include "b2r2_timing.h" +#include "b2r2_debug.h" + +/** + * 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) + +/** + * 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 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; + + /* Sanity checks */ + BUG_ON(core == NULL); + BUG_ON(job == NULL); + + b2r2_log_info(core->dev, "%s (core: %p, job: %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: (core: %p, job: %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 (core: %p, job: %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 (core: %p, job: %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: (core: %p, job: %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 (core: %p, job: %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_core *core; + + BUG_ON(job == NULL || job->data == 0); + core = (struct b2r2_core *) job->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_core *core; + + BUG_ON(job == NULL || job->data == 0); + core = (struct b2r2_core *) job->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 (core: %p, job: %p)\n", + __func__, core, job); + + /* Enable B2R2 */ + domain_enable(core); + + spin_lock_irqsave(&core->lock, flags); + /* Check that we have not been powered down */ + if (!core->domain_enabled) { + spin_unlock_irqrestore(&core->lock, flags); + return -ENOSYS; + } + + 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 job->job_id; +} + +/** + * 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 (core: %p, job_id: %d)\n", + __func__, core, 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 (core: %p, tag: %d)\n", __func__, core, 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_core *core = (struct b2r2_core *) job->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; +#ifdef CONFIG_B2R2_DEBUG + struct b2r2_core *core = (struct b2r2_core *) job->data; +#endif + + b2r2_log_info(core->dev, "%s (core: %p, job: %p)\n", + __func__, core, 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_core *core = (struct b2r2_core *) job->data; + + b2r2_log_info(core->dev, "%s (core: %p, job: %p) (st: %d)\n", + __func__, core, 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) { + core->valid = false; + 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; + + ret = clk_enable(core->b2r2_clock); + if (ret < 0) { + b2r2_log_err(core->dev, + "%s: Could not enable clock\n", __func__); + goto enable_clk_failed; + } + if (init_hw(core) < 0) + goto init_hw_failed; + core->domain_enabled = true; + core->valid = 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); + +enable_clk_failed: + 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__); + + } +} + +/** + * 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_core *core = (struct b2r2_core *) job->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 > JOB_TIMEOUT) { + /* Active jobs and more than a second since last irq! */ + int i; + + b2r2_core_print_stats(core); + + /* 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, JOB_TIMEOUT); + + 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) +{ + + job->start_sentinel = START_SENTINEL; + job->end_sentinel = END_SENTINEL; + + /* 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, JOB_TIMEOUT); +#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_core *core = (struct b2r2_core *) job->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_RESET_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) + * @dev_id: A pointer to the b2r2 core entity + */ +static irqreturn_t b2r2_irq_handler(int irq, void *dev_id) +{ + unsigned long flags; + struct b2r2_core* core = (struct b2r2_core *) dev_id; + + /* Spin lock is need in irq handler (SMP) */ + spin_lock_irqsave(&core->lock, flags); + + /* Make a quick exit if this device was not interrupting */ + if (!core->valid || + ((readl(&core->hw->BLT_ITS) & B2R2_ITS_MASK) == 0)) { + core->stat_n_irq_skipped++; + spin_unlock_irqrestore(&core->lock, flags); + return IRQ_NONE; + } + + /* 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); + + core->stat_n_irq_exit++; + + 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 *tmpbuf = kmalloc(sizeof(char) * 4096, GFP_KERNEL); + + if (tmpbuf == 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(tmpbuf, "%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, tmpbuf, count)) + ret = -EINVAL; + *f_pos += count; + ret = count; + +out: + if (tmpbuf != NULL) + kfree(tmpbuf); + 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 tmpbuf[80]; + u32 reg_value; + int ret = 0; + + /* Adjust count */ + if (count >= sizeof(tmpbuf)) + count = sizeof(tmpbuf) - 1; + /* Get it from user space */ + if (copy_from_user(tmpbuf, buf, count)) + return -EINVAL; + tmpbuf[count] = 0; + /* Convert from hex string */ + if (sscanf(tmpbuf, "%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 *tmpbuf = kmalloc(sizeof(char) * 4096, GFP_KERNEL); + + if (tmpbuf == 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(tmpbuf + 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, tmpbuf, count)) + ret = -EINVAL; + *f_pos += count; + ret = count; + +out: + if (tmpbuf != NULL) + kfree(tmpbuf); + 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 *tmpbuf = kmalloc(sizeof(char) * 4096, GFP_KERNEL); + struct b2r2_core *core = filp->f_dentry->d_inode->i_private; + + if (tmpbuf == NULL) { + ret = -ENOMEM; + goto out; + } + + /* Build a string containing all statistics */ + dev_size += sprintf(tmpbuf + dev_size, "Interrupts : %lu\n", + core->stat_n_irq); + dev_size += sprintf(tmpbuf + dev_size, "Added jobs : %lu\n", + core->stat_n_jobs_added); + dev_size += sprintf(tmpbuf + dev_size, "Removed jobs : %lu\n", + core->stat_n_jobs_removed); + dev_size += sprintf(tmpbuf + dev_size, "Jobs in prio list : %lu\n", + core->stat_n_jobs_in_prio_list); + dev_size += sprintf(tmpbuf + dev_size, "Active jobs : %lu\n", + core->n_active_jobs); + for (i = 0; i < ARRAY_SIZE(core->active_jobs); i++) + dev_size += sprintf(tmpbuf + dev_size, + " Job in queue %d : 0x%08lx\n", + i, (unsigned long) core->active_jobs[i]); + dev_size += sprintf(tmpbuf + 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, tmpbuf, count)) + ret = -EINVAL; + *f_pos += count; + ret = count; + +out: + if (tmpbuf != NULL) + kfree(tmpbuf); + 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 tmpbuf[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(tmpbuf, "%#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, tmpbuf, 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 tmpbuf[80]; + u32 reg_value; + int ret = 0; + + if (count >= sizeof(tmpbuf)) + count = sizeof(tmpbuf) - 1; + if (copy_from_user(tmpbuf, buf, count)) + return -EINVAL; + tmpbuf[count] = 0; + if (sscanf(tmpbuf, "%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, +}; + +/** + * debugfs_b2r2_enabled_read() - Implements debugfs read for + * B2R2 Core Enable/Disable + * @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_enabled_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + /* 4 characters hex number + newline + string terminator; */ + char tmpbuf[4+2]; + size_t dev_size; + int ret = 0; + struct b2r2_core *core = filp->f_dentry->d_inode->i_private; + + dev_size = sprintf(tmpbuf, "%02X\n", core->control->enabled); + + /* 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, tmpbuf, count)) + ret = -EINVAL; + *f_pos += count; + ret = count; +out: + return ret; +} + +/** + * debugfs_b2r2_enabled_write() - Implements debugfs write for + * B2R2 Core Enable/Disable + * @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_enabled_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + char tmpbuf[80]; + unsigned int enable; + int ret = 0; + struct b2r2_core *core = filp->f_dentry->d_inode->i_private; + + if (count >= sizeof(tmpbuf)) + count = sizeof(tmpbuf) - 1; + if (copy_from_user(tmpbuf, buf, count)) + return -EINVAL; + tmpbuf[count] = 0; + if (sscanf(tmpbuf, "%02X", &enable) != 1) + return -EINVAL; + + if (enable) + core->control->enabled = true; + else + core->control->enabled = false; + + *f_pos += count; + ret = count; + + return ret; +} + +/** + * debugfs_b2r2_enabled_fops() - File operations for B2R2 Core Enable/Disable debugfs + */ +static const struct file_operations debugfs_b2r2_enabled_fops = { + .owner = THIS_MODULE, + .read = debugfs_b2r2_enabled_read, + .write = debugfs_b2r2_enabled_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_RESET_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, IRQF_SHARED, + "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 (!IS_ERR_OR_NULL(core->debugfs_core_root_dir) && + IS_ERR_OR_NULL(core->debugfs_regs_dir)) { + core->debugfs_regs_dir = debugfs_create_dir("regs", + core->debugfs_core_root_dir); + } + if (!IS_ERR_OR_NULL(core->debugfs_regs_dir)) { + int i; + 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 (!IS_ERR_OR_NULL(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 = NULL; + struct b2r2_core *core = NULL; + struct b2r2_control *control = NULL; + struct b2r2_platform_data *pdata = NULL; + int debug_init = 0; + + BUG_ON(pdev == NULL); + BUG_ON(pdev->id < 0 || pdev->id >= B2R2_MAX_NBR_DEVICES); + + pdata = pdev->dev.platform_data; + + core = kzalloc(sizeof(*core), GFP_KERNEL); + if (!core) { + dev_err(&pdev->dev, "b2r2 core alloc failed\n"); + ret = -EINVAL; + goto error_exit; + } + + 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 error_exit; + } + + /* Get the clock for B2R2 */ + core->b2r2_clock = clk_get(core->dev, pdata->clock_id); + if (IS_ERR(core->b2r2_clock)) { + ret = PTR_ERR(core->b2r2_clock); + dev_err(&pdev->dev, "clk_get %s failed\n", pdata->clock_id); + goto error_exit; + } + + /* Get the B2R2 regulator */ + core->b2r2_reg = regulator_get(core->dev, pdata->regulator_id); + if (IS_ERR(core->b2r2_reg)) { + ret = PTR_ERR(core->b2r2_reg); + dev_err(&pdev->dev, "regulator_get %s failed " + "(dev_name=%s)\n", pdata->regulator_id, + dev_name(core->dev)); + goto error_exit; + } + + /* Init power management */ + mutex_init(&core->domain_lock); + INIT_DELAYED_WORK_DEFERRABLE(&core->domain_disable_work, + domain_disable_work_function); + core->domain_enabled = false; + core->valid = false; + + /* Map B2R2 into kernel virtual memory space */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) + goto error_exit; + + /* 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 error_exit; + } + + 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 error_exit; + } + + 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 error_exit; + } + + control->data = (void *)core; + control->id = pdev->id; + control->dev = &pdev->dev; /* Temporary device */ + + 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); + if (!IS_ERR_OR_NULL(core->debugfs_root_dir)) { + core->debugfs_core_root_dir = debugfs_create_dir("core", + core->debugfs_root_dir); + 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); + } + + if (!IS_ERR_OR_NULL(core->debugfs_core_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_file("enabled", 0666, + core->debugfs_core_root_dir, + core, &debugfs_b2r2_enabled_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); + } +#endif + + ret = b2r2_debug_init(control); + if (ret < 0) { + dev_err(&pdev->dev, "b2r2_debug_init failed\n"); + goto error_exit; + } + debug_init = 1; + + /* Initialize b2r2_control */ + ret = b2r2_control_init(control); + if (ret < 0) { + b2r2_log_err(&pdev->dev, "b2r2_control_init failed\n"); + goto error_exit; + } + core->control = control; + + /* Add the control to the blitter */ + kref_init(&control->ref); + control->enabled = true; + b2r2_blt_add_control(control); + + b2r2_core[pdev->id] = core; + dev_info(&pdev->dev, "%s done.\n", __func__); + + return ret; + +/** Recover from any error if something fails */ +error_exit: + kfree(control); + + if (!IS_ERR_OR_NULL(core->b2r2_reg)) + regulator_put(core->b2r2_reg); + + if (!IS_ERR_OR_NULL(core->b2r2_clock)) + clk_put(core->b2r2_clock); + + if (!IS_ERR_OR_NULL(core->work_queue)) + destroy_workqueue(core->work_queue); + + if (debug_init) + b2r2_debug_exit(); + +#ifdef CONFIG_DEBUG_FS + if (!IS_ERR_OR_NULL(core->debugfs_root_dir)) { + debugfs_remove_recursive(core->debugfs_root_dir); + core->debugfs_root_dir = NULL; + } +#endif + kfree(core); + + dev_info(&pdev->dev, "%s done with errors (%d).\n", __func__, ret); + + return ret; +} + +void b2r2_core_release(struct kref *control_ref) +{ + struct b2r2_control *control = container_of( + control_ref, struct b2r2_control, ref); + struct b2r2_core *core = control->data; + int id = control->id; + unsigned long flags; +#ifdef CONFIG_B2R2_DEBUG + struct device *dev = core->dev; +#endif + + b2r2_log_info(dev, "%s: enter\n", __func__); + + /* Exit b2r2 control module */ + b2r2_control_exit(control); + kfree(control); + b2r2_debug_exit(); + +#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(dev, "%s: unmap b2r2 registers..\n", __func__); + 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[id] = NULL; + + b2r2_log_info(dev, "%s: exit\n", __func__); +} + + +/** + * b2r2_remove - This routine unloads b2r2 driver + * + * @pdev: platform device. + */ +static int b2r2_remove(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(&pdev->dev, "%s: Started\n", __func__); + +#ifdef CONFIG_DEBUG_FS + if (!IS_ERR_OR_NULL(core->debugfs_root_dir)) { + debugfs_remove_recursive(core->debugfs_root_dir); + core->debugfs_root_dir = NULL; + } +#endif + + /* Flush B2R2 work queue (call all callbacks) */ + flush_workqueue(core->work_queue); + + /* Remove control from blitter */ + core->control->enabled = false; + b2r2_blt_remove_control(core->control); + kref_put(&core->control->ref, b2r2_core_release); + + 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; +} + +void b2r2_core_print_stats(struct b2r2_core *core) +{ + b2r2_log_info(core->dev, + "%s: n_irq %ld, n_irq_exit %ld, n_irq_skipped %ld,\n" + "n_jobs_added %ld, n_active_jobs %ld, " + "n_jobs_in_prio_list %ld,\n" + "n_jobs_removed %ld\n", + __func__, + core->stat_n_irq, + core->stat_n_irq_exit, + core->stat_n_irq_skipped, + core->stat_n_jobs_added, + core->n_active_jobs, + core->stat_n_jobs_in_prio_list, + core->stat_n_jobs_removed); +} + +/** + * 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..5b9fdcdc2bb --- /dev/null +++ b/drivers/video/b2r2/b2r2_core.h @@ -0,0 +1,300 @@ +/* + * 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_RESET_TIMEOUT_VALUE - The number of times to read the status register + * waiting for b2r2 to go idle after soft reset. + */ +#define B2R2_RESET_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 +#define JOB_TIMEOUT (HZ/2) +#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 + + +#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_exit; + unsigned long stat_n_irq_skipped; + 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; + volatile bool valid; + int domain_request_count; + + struct clk *b2r2_clock; + struct regulator *b2r2_reg; + + struct b2r2_control *control; +}; + +/** + * 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); + +void b2r2_core_print_stats(struct b2r2_core *core); + +void b2r2_core_release(struct kref *control_ref); + +#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..934ba938ee5 --- /dev/null +++ b/drivers/video/b2r2/b2r2_debug.c @@ -0,0 +1,340 @@ +/* + * 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 */ + if (!IS_ERR_OR_NULL(log_lvl_dir)) { + (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 (!IS_ERR_OR_NULL(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 && !IS_ERR_OR_NULL(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..a93eb60d91f --- /dev/null +++ b/drivers/video/b2r2/b2r2_filters.c @@ -0,0 +1,377 @@ +/* + * 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" +#include "b2r2_debug.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 = { + 0x00, 0x00, 0xFA, 0x09, 0x34, 0x09, 0x00, 0x00, + 0x00, 0x00, 0xF9, 0x10, 0x32, 0x06, 0xFF, 0x00, + 0x00, 0x00, 0xF8, 0x17, 0x2F, 0x02, 0x00, 0x00, + 0x00, 0x00, 0xF7, 0x20, 0x2A, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0xF8, 0x27, 0x25, 0xFC, 0x00, 0x00, + 0x00, 0x00, 0xFA, 0x2D, 0x1D, 0xFC, 0x00, 0x00, + 0x00, 0x00, 0xFE, 0x31, 0x15, 0xFC, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x35, 0x0D, 0xFC, 0x00, 0x00 + }, + .v_coeffs = { + 0x00, 0x02, 0x3C, 0x02, 0x00, + 0x00, 0x08, 0x3B, 0xFD, 0x00, + 0x00, 0x10, 0x35, 0xFB, 0x00, + 0x00, 0x18, 0x30, 0xF8, 0x00, + 0x00, 0x1F, 0x27, 0xFA, 0x00, + 0x00, 0x27, 0x1E, 0xFB, 0x00, + 0x00, 0x2E, 0x16, 0xFC, 0x00, + 0x00, 0x34, 0x0D, 0xFF, 0x00 + }, + }, + { + .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..4191e497e13 --- /dev/null +++ b/drivers/video/b2r2/b2r2_generic.c @@ -0,0 +1,3206 @@ +/* + * 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" +#include "b2r2_hw_convert.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; + bool fullrange = (req->user_req.flags & + B2R2_BLT_FLAG_FULL_RANGE_YUV) != 0; + + 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. + */ + b2r2_setup_ivmx(node, B2R2_CC_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. + */ + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_BLT_YUV888_FULL_TO_RGB); + else + b2r2_setup_ivmx(node, B2R2_CC_BLT_YUV888_TO_RGB); + } 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: + if (fullrange) + b2r2_setup_ivmx(node, + B2R2_CC_BLT_YUV888_FULL_TO_RGB); + else + b2r2_setup_ivmx(node, + B2R2_CC_BLT_YUV888_TO_RGB); + /* + * 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. + */ + if (fullrange) + b2r2_setup_ivmx(node, + B2R2_CC_YVU_FULL_TO_RGB); + else + b2r2_setup_ivmx(node, B2R2_CC_YVU_TO_RGB); + 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. + */ + if (fullrange) + b2r2_setup_ivmx(node, + B2R2_CC_YUV_FULL_TO_RGB); + else + b2r2_setup_ivmx(node, B2R2_CC_YUV_TO_RGB); + 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; + bool fullrange = (req->user_req.flags & + B2R2_BLT_FLAG_FULL_RANGE_YUV) != 0; + + 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: + b2r2_setup_ivmx(node, B2R2_CC_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. + */ + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_YVU_FULL_TO_RGB); + else + b2r2_setup_ivmx(node, B2R2_CC_YVU_TO_RGB); + break; + case B2R2_BLT_FMT_CB_Y_CR_Y: + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_YUV_FULL_TO_RGB); + else + b2r2_setup_ivmx(node, B2R2_CC_YUV_TO_RGB); + 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. + */ + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_BLT_YUV888_FULL_TO_RGB); + else + b2r2_setup_ivmx(node, B2R2_CC_BLT_YUV888_TO_RGB); + + /* + * 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; + + node->node.GROUP0.B2R2_INS |= B2R2_INS_RESCALE2D_ENABLED; + node->node.GROUP0.B2R2_CIC |= 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) { + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_YVU_FULL_TO_RGB); + else + b2r2_setup_ivmx(node, B2R2_CC_YVU_TO_RGB); + } else { + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_YUV_FULL_TO_RGB); + else + b2r2_setup_ivmx(node, B2R2_CC_YUV_TO_RGB); + } + + 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; + bool fullrange = (req->user_req.flags & + B2R2_BLT_FLAG_FULL_RANGE_YUV) != 0; + + 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: + b2r2_setup_ivmx(node, B2R2_CC_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. + */ + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_YVU_FULL_TO_RGB); + else + b2r2_setup_ivmx(node, B2R2_CC_YVU_TO_RGB); + break; + case B2R2_BLT_FMT_CB_Y_CR_Y: + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_YUV_FULL_TO_RGB); + else + b2r2_setup_ivmx(node, B2R2_CC_YUV_TO_RGB); + 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. + */ + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_BLT_YUV888_FULL_TO_RGB); + else + b2r2_setup_ivmx(node, B2R2_CC_BLT_YUV888_TO_RGB); + + /* + * 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: { + if (dst_img->fmt == B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR || + dst_img->fmt == + B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR) { + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_YVU_FULL_TO_RGB); + else + b2r2_setup_ivmx(node, B2R2_CC_YVU_TO_RGB); + } else { + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_YUV_FULL_TO_RGB); + else + b2r2_setup_ivmx(node, B2R2_CC_YUV_TO_RGB); + } + + 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; + bool fullrange = (req->user_req.flags & + B2R2_BLT_FLAG_FULL_RANGE_YUV) != 0; + + 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; + const u32 group0_b2r2_cic = + B2R2_CIC_SOURCE_2 | + B2R2_CIC_CLIP_WINDOW; + + 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; + + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_RGB_TO_YUV_FULL); + else + b2r2_setup_ivmx(node, B2R2_CC_RGB_TO_YUV); + + /* 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; + + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_RGB_TO_YUV_FULL); + else + b2r2_setup_ivmx(node, B2R2_CC_RGB_TO_YUV); + + 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; + + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_RGB_TO_YUV_FULL); + else + b2r2_setup_ivmx(node, B2R2_CC_RGB_TO_YUV); + + 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; + const u32 group0_b2r2_cic = + B2R2_CIC_SOURCE_2 | + B2R2_CIC_CLIP_WINDOW; + + 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) { + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_RGB_TO_YVU_FULL); + else + b2r2_setup_ivmx(node, B2R2_CC_RGB_TO_YVU); + } else { + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_RGB_TO_YUV_FULL); + else + b2r2_setup_ivmx(node, B2R2_CC_RGB_TO_YUV); + } + + /* 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) { + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_RGB_TO_YVU_FULL); + else + b2r2_setup_ivmx(node, B2R2_CC_RGB_TO_YVU); + } else { + if (fullrange) + b2r2_setup_ivmx(node, B2R2_CC_RGB_TO_YUV_FULL); + else + b2r2_setup_ivmx(node, B2R2_CC_RGB_TO_YUV); + } + + 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 */ + + switch (dst_fmt) { + case B2R2_BLT_FMT_32_BIT_ABGR8888: + b2r2_setup_ovmx(node, B2R2_CC_RGB_TO_BGR); + break; + case B2R2_BLT_FMT_Y_CB_Y_CR: + if (fullrange) + b2r2_setup_ovmx(node, B2R2_CC_RGB_TO_YVU_FULL); + else + b2r2_setup_ovmx(node, B2R2_CC_RGB_TO_YVU); + 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: + if (fullrange) + b2r2_setup_ovmx(node, B2R2_CC_RGB_TO_BLT_YUV888_FULL); + else + b2r2_setup_ovmx(node, B2R2_CC_RGB_TO_BLT_YUV888); + /* + * 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..9739912d78c --- /dev/null +++ b/drivers/video/b2r2/b2r2_hw.h @@ -0,0 +1,458 @@ +/* + * 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 + +#endif /* B2R2_HW_H__ */ diff --git a/drivers/video/b2r2/b2r2_hw_convert.c b/drivers/video/b2r2/b2r2_hw_convert.c new file mode 100644 index 00000000000..d1b44db79c3 --- /dev/null +++ b/drivers/video/b2r2/b2r2_hw_convert.c @@ -0,0 +1,747 @@ +/* + * Copyright (C) ST-Ericsson SA 2012 + * + * ST-Ericsson B2R2 node splitter + * + * Author: Jorgen Nilsson <jorgen.nilsson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include "b2r2_hw_convert.h" +#include "b2r2_internal.h" +#include "b2r2_utils.h" + +/* + * Macros and constants + */ + +/* VMX register values for RGB to YUV color conversion */ +/* Magic numbers from 27.11 in DB8500_DesignSpecification_v2.5.pdf */ + +/* 601 Full range conversion matrix */ +#define B2R2_VMX0_RGB_TO_YUV_601_FULL_RANGE 0x107e4beb +#define B2R2_VMX1_RGB_TO_YUV_601_FULL_RANGE 0x0982581d +#define B2R2_VMX2_RGB_TO_YUV_601_FULL_RANGE 0xfa9ea483 +#define B2R2_VMX3_RGB_TO_YUV_601_FULL_RANGE 0x08000080 + +/* 601 Standard (clamped) conversion matrix */ +#define B2R2_VMX0_RGB_TO_YUV_601_STANDARD 0x0e1e8bee +#define B2R2_VMX1_RGB_TO_YUV_601_STANDARD 0x08420419 +#define B2R2_VMX2_RGB_TO_YUV_601_STANDARD 0xfb5ed471 +#define B2R2_VMX3_RGB_TO_YUV_601_STANDARD 0x08004080 + +/* 709 Full range conversion matrix */ +#define B2R2_VMX0_RGB_TO_YUV_709_FULL_RANGE 0x107e27f4 +#define B2R2_VMX1_RGB_TO_YUV_709_FULL_RANGE 0x06e2dc13 +#define B2R2_VMX2_RGB_TO_YUV_709_FULL_RANGE 0xfc5e6c83 +#define B2R2_VMX3_RGB_TO_YUV_709_FULL_RANGE 0x08000080 + +/* 709 Standard (clamped) conversion matrix */ +#define B2R2_VMX0_RGB_TO_YUV_709_STANDARD 0x0e3e6bf5 +#define B2R2_VMX1_RGB_TO_YUV_709_STANDARD 0x05e27410 +#define B2R2_VMX2_RGB_TO_YUV_709_STANDARD 0xfcdea471 +#define B2R2_VMX3_RGB_TO_YUV_709_STANDARD 0x08004080 + +/* VMX register values for YUV to RGB color conversion */ + +/* 601 Full range conversion matrix */ +#define B2R2_VMX0_YUV_TO_RGB_601_FULL_RANGE 0x2c440000 +#define B2R2_VMX1_YUV_TO_RGB_601_FULL_RANGE 0xe9a403aa +#define B2R2_VMX2_YUV_TO_RGB_601_FULL_RANGE 0x0004013f +#define B2R2_VMX3_YUV_TO_RGB_601_FULL_RANGE 0x34f21322 + +/* 601 Standard (clamped) conversion matrix */ +#define B2R2_VMX0_YUV_TO_RGB_601_STANDARD 0x3324a800 +#define B2R2_VMX1_YUV_TO_RGB_601_STANDARD 0xe604ab9c +#define B2R2_VMX2_YUV_TO_RGB_601_STANDARD 0x0004a957 +#define B2R2_VMX3_YUV_TO_RGB_601_STANDARD 0x32121eeb + +/* 709 Full range conversion matrix */ +#define B2R2_VMX0_YUV_TO_RGB_709_FULL_RANGE 0x31440000 +#define B2R2_VMX1_YUV_TO_RGB_709_FULL_RANGE 0xf16403d1 +#define B2R2_VMX2_YUV_TO_RGB_709_FULL_RANGE 0x00040145 +#define B2R2_VMX3_YUV_TO_RGB_709_FULL_RANGE 0x33b14b18 + +/* 709 Standard (clamped) conversion matrix */ +#define B2R2_VMX0_YUV_TO_RGB_709_STANDARD 0x3964a800 +#define B2R2_VMX1_YUV_TO_RGB_709_STANDARD 0xef04abc9 +#define B2R2_VMX2_YUV_TO_RGB_709_STANDARD 0x0004a95f +#define B2R2_VMX3_YUV_TO_RGB_709_STANDARD 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 Full range conversion matrix */ +#define B2R2_VMX0_BGR_TO_YUV_601_FULL_RANGE 0xfd7e4883 +#define B2R2_VMX1_BGR_TO_YUV_601_FULL_RANGE 0x03a2584c +#define B2R2_VMX2_BGR_TO_YUV_601_FULL_RANGE 0x107ea7d4 +#define B2R2_VMX3_BGR_TO_YUV_601_FULL_RANGE 0x08000080 + +/* 601 Standard (clamped) conversion matrix */ +#define B2R2_VMX0_BGR_TO_YUV_601_STANDARD 0xfdde8870 +#define B2R2_VMX1_BGR_TO_YUV_601_STANDARD 0x03220442 +#define B2R2_VMX2_BGR_TO_YUV_601_STANDARD 0x0e3ed7da +#define B2R2_VMX3_BGR_TO_YUV_601_STANDARD 0x08004080 + +/* 709 Full range conversion matrix */ +#define B2R2_VMX0_BGR_TO_YUV_709_FULL_RANGE 0xfe9e2483 +#define B2R2_VMX1_BGR_TO_YUV_709_FULL_RANGE 0x0262dc37 +#define B2R2_VMX2_BGR_TO_YUV_709_FULL_RANGE 0x107e6fe2 +#define B2R2_VMX3_BGR_TO_YUV_709_FULL_RANGE 0x08000080 + +/* 709 Standard (clamped) conversion matrix */ +#define B2R2_VMX0_BGR_TO_YUV_709_STANDARD 0xfebe6871 +#define B2R2_VMX1_BGR_TO_YUV_709_STANDARD 0x0202742f +#define B2R2_VMX2_BGR_TO_YUV_709_STANDARD 0x0e3ea7e6 +#define B2R2_VMX3_BGR_TO_YUV_709_STANDARD 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 Full range conversion matrix */ +#define B2R2_VMX0_YUV_TO_BGR_601_FULL_RANGE (B2R2_VMX2_YUV_TO_RGB_601_FULL_RANGE) +#define B2R2_VMX1_YUV_TO_BGR_601_FULL_RANGE (B2R2_VMX1_YUV_TO_RGB_601_FULL_RANGE) +#define B2R2_VMX2_YUV_TO_BGR_601_FULL_RANGE (B2R2_VMX0_YUV_TO_RGB_601_FULL_RANGE) +#define B2R2_VMX3_YUV_TO_BGR_601_FULL_RANGE 0x3222134f + +/* 601 Standard (clamped) conversion matrix */ +#define B2R2_VMX0_YUV_TO_BGR_601_STANDARD (B2R2_VMX2_YUV_TO_RGB_601_STANDARD) +#define B2R2_VMX1_YUV_TO_BGR_601_STANDARD (B2R2_VMX1_YUV_TO_RGB_601_STANDARD) +#define B2R2_VMX2_YUV_TO_BGR_601_STANDARD (B2R2_VMX0_YUV_TO_RGB_601_STANDARD) +#define B2R2_VMX3_YUV_TO_BGR_601_STANDARD 0x2eb21f21 + +/* 709 Full range conversion matrix */ +#define B2R2_VMX0_YUV_TO_BGR_709_FULL_RANGE (B2R2_VMX2_YUV_TO_RGB_709_FULL_RANGE) +#define B2R2_VMX1_YUV_TO_BGR_709_FULL_RANGE (B2R2_VMX1_YUV_TO_RGB_709_FULL_RANGE) +#define B2R2_VMX2_YUV_TO_BGR_709_FULL_RANGE (B2R2_VMX0_YUV_TO_RGB_709_FULL_RANGE) +#define B2R2_VMX3_YUV_TO_BGR_709_FULL_RANGE 0x31814b3b + +/* 709 Standard (clamped) conversion matrix */ +#define B2R2_VMX0_YUV_TO_BGR_709_STANDARD (B2R2_VMX2_YUV_TO_RGB_709_STANDARD) +#define B2R2_VMX1_YUV_TO_BGR_709_STANDARD (B2R2_VMX1_YUV_TO_RGB_709_STANDARD) +#define B2R2_VMX2_YUV_TO_BGR_709_STANDARD (B2R2_VMX0_YUV_TO_RGB_709_STANDARD) +#define B2R2_VMX3_YUV_TO_BGR_709_STANDARD 0x2df13307 + + +/* VMX register values for YVU to RGB conversion */ + +/* 601 Full range conversion matrix */ +#define B2R2_VMX0_YVU_TO_RGB_601_FULL_RANGE 0x00040120 +#define B2R2_VMX1_YVU_TO_RGB_601_FULL_RANGE 0xF544034D +#define B2R2_VMX2_YVU_TO_RGB_601_FULL_RANGE 0x37840000 +#define B2R2_VMX3_YVU_TO_RGB_601_FULL_RANGE (B2R2_VMX3_YUV_TO_RGB_601_FULL_RANGE) + +/* 601 Standard (clamped) conversion matrix */ +#define B2R2_VMX0_YVU_TO_RGB_601_STANDARD 0x0004A999 +#define B2R2_VMX1_YVU_TO_RGB_601_STANDARD 0xF384AB30 +#define B2R2_VMX2_YVU_TO_RGB_601_STANDARD 0x40A4A800 +#define B2R2_VMX3_YVU_TO_RGB_601_STANDARD (B2R2_VMX3_YUV_TO_RGB_601_STANDARD) + +/* VMX register values for RGB to YVU conversion */ + +/* 601 Full range conversion matrix */ +#define B2R2_VMX0_RGB_TO_YVU_601_FULL_RANGE (B2R2_VMX2_RGB_TO_YUV_601_FULL_RANGE) +#define B2R2_VMX1_RGB_TO_YVU_601_FULL_RANGE (B2R2_VMX1_RGB_TO_YUV_601_FULL_RANGE) +#define B2R2_VMX2_RGB_TO_YVU_601_FULL_RANGE (B2R2_VMX0_RGB_TO_YUV_601_FULL_RANGE) +#define B2R2_VMX3_RGB_TO_YVU_601_FULL_RANGE (B2R2_VMX3_RGB_TO_YUV_601_FULL_RANGE) + +/* 601 Standard (clamped) conversion matrix */ +#define B2R2_VMX0_RGB_TO_YVU_601_STANDARD (B2R2_VMX2_RGB_TO_YUV_601_STANDARD) +#define B2R2_VMX1_RGB_TO_YVU_601_STANDARD (B2R2_VMX1_RGB_TO_YUV_601_STANDARD) +#define B2R2_VMX2_RGB_TO_YVU_601_STANDARD (B2R2_VMX0_RGB_TO_YUV_601_STANDARD) +#define B2R2_VMX3_RGB_TO_YVU_601_STANDARD (B2R2_VMX3_RGB_TO_YUV_601_STANDARD) + +/* VMX register values for YVU to BGR conversion */ + +/* 601 Full range conversion matrix */ +#define B2R2_VMX0_YVU_TO_BGR_601_FULL_RANGE (B2R2_VMX2_YVU_TO_RGB_601_FULL_RANGE) +#define B2R2_VMX1_YVU_TO_BGR_601_FULL_RANGE (B2R2_VMX1_YVU_TO_RGB_601_FULL_RANGE) +#define B2R2_VMX2_YVU_TO_BGR_601_FULL_RANGE (B2R2_VMX0_YVU_TO_RGB_601_FULL_RANGE) +#define B2R2_VMX3_YVU_TO_BGR_601_FULL_RANGE 0x3222134F + +/* 601 Standard (clamped) conversion matrix */ +#define B2R2_VMX0_YVU_TO_BGR_601_STANDARD (B2R2_VMX2_YVU_TO_RGB_601_STANDARD) +#define B2R2_VMX1_YVU_TO_BGR_601_STANDARD (B2R2_VMX1_YVU_TO_RGB_601_STANDARD) +#define B2R2_VMX2_YVU_TO_BGR_601_STANDARD (B2R2_VMX0_YVU_TO_RGB_601_STANDARD) +#define B2R2_VMX3_YVU_TO_BGR_601_STANDARD 0x3222134F + +/* VMX register values for BGR to YVU conversion */ + +/* 601 Full range conversion matrix */ +#define B2R2_VMX0_BGR_TO_YVU_601_FULL_RANGE (B2R2_VMX2_BGR_TO_YUV_601_FULL_RANGE) +#define B2R2_VMX1_BGR_TO_YVU_601_FULL_RANGE (B2R2_VMX1_BGR_TO_YUV_601_FULL_RANGE) +#define B2R2_VMX2_BGR_TO_YVU_601_FULL_RANGE (B2R2_VMX0_BGR_TO_YUV_601_FULL_RANGE) +#define B2R2_VMX3_BGR_TO_YVU_601_FULL_RANGE (B2R2_VMX3_BGR_TO_YUV_601_FULL_RANGE) + +/* 601 Standard (clamped) conversion matrix */ +#define B2R2_VMX0_BGR_TO_YVU_601_STANDARD (B2R2_VMX2_BGR_TO_YUV_601_STANDARD) +#define B2R2_VMX1_BGR_TO_YVU_601_STANDARD (B2R2_VMX1_BGR_TO_YUV_601_STANDARD) +#define B2R2_VMX2_BGR_TO_YVU_601_STANDARD (B2R2_VMX0_BGR_TO_YUV_601_STANDARD) +#define B2R2_VMX3_BGR_TO_YVU_601_STANDARD (B2R2_VMX3_BGR_TO_YUV_601_STANDARD) + +/* 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 0x00000100 +#define B2R2_VMX1_YVU_TO_YUV 0x00040000 +#define B2R2_VMX2_YVU_TO_YUV 0x20000000 +#define B2R2_VMX3_YVU_TO_YUV 0x00000000 + +/* VMX register values for RGB to BLT_YUV888 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. + */ +/* 601 Full range conversion matrix */ +#define B2R2_VMX0_RGB_TO_BLT_YUV888_601_FULL_RANGE (B2R2_VMX1_RGB_TO_YUV_601_FULL_RANGE) +#define B2R2_VMX1_RGB_TO_BLT_YUV888_601_FULL_RANGE (B2R2_VMX2_RGB_TO_YUV_601_FULL_RANGE) +#define B2R2_VMX2_RGB_TO_BLT_YUV888_601_FULL_RANGE (B2R2_VMX0_RGB_TO_YUV_601_FULL_RANGE) +#define B2R2_VMX3_RGB_TO_BLT_YUV888_601_FULL_RANGE 0x00020080 + +/* 601 Standard (clamped) conversion matrix */ +#define B2R2_VMX0_RGB_TO_BLT_YUV888_601_STANDARD (B2R2_VMX1_RGB_TO_YUV_601_STANDARD) +#define B2R2_VMX1_RGB_TO_BLT_YUV888_601_STANDARD (B2R2_VMX2_RGB_TO_YUV_601_STANDARD) +#define B2R2_VMX2_RGB_TO_BLT_YUV888_601_STANDARD (B2R2_VMX0_RGB_TO_YUV_601_STANDARD) +#define B2R2_VMX3_RGB_TO_BLT_YUV888_601_STANDARD 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. + */ +/* 601 Full range conversion matrix */ +#define B2R2_VMX0_BLT_YUV888_TO_RGB_601_FULL_RANGE 0x20000121 +#define B2R2_VMX1_BLT_YUV888_TO_RGB_601_FULL_RANGE 0x201ea74c +#define B2R2_VMX2_BLT_YUV888_TO_RGB_601_FULL_RANGE 0x2006f000 +#define B2R2_VMX3_BLT_YUV888_TO_RGB_601_FULL_RANGE (B2R2_VMX3_YUV_TO_RGB_601_FULL_RANGE) + +/* 601 Standard (clamped) conversion matrix */ +#define B2R2_VMX0_BLT_YUV888_TO_RGB_601_STANDARD 0x25400133 +#define B2R2_VMX1_BLT_YUV888_TO_RGB_601_STANDARD 0x255E7330 +#define B2R2_VMX2_BLT_YUV888_TO_RGB_601_STANDARD 0x25481400 +#define B2R2_VMX3_BLT_YUV888_TO_RGB_601_STANDARD (B2R2_VMX3_YUV_TO_RGB_601_FULL_RANGE) + +/* 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 + +/* + * Internal types + */ + +/* + * Global variables + */ + + /** + * VMx values for color space conversion + * (component swap) + */ +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_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_yvu_to_yuv[] = { + B2R2_VMX0_YVU_TO_YUV, + B2R2_VMX1_YVU_TO_YUV, + B2R2_VMX2_YVU_TO_YUV, + B2R2_VMX3_YVU_TO_YUV, +}; + +/** + * VMx values for color space conversions + * (standard 601 conversions) + */ +static const u32 vmx_rgb_to_yuv[] = { + B2R2_VMX0_RGB_TO_YUV_601_STANDARD, + B2R2_VMX1_RGB_TO_YUV_601_STANDARD, + B2R2_VMX2_RGB_TO_YUV_601_STANDARD, + B2R2_VMX3_RGB_TO_YUV_601_STANDARD, +}; + +static const u32 vmx_yuv_to_rgb[] = { + B2R2_VMX0_YUV_TO_RGB_601_STANDARD, + B2R2_VMX1_YUV_TO_RGB_601_STANDARD, + B2R2_VMX2_YUV_TO_RGB_601_STANDARD, + B2R2_VMX3_YUV_TO_RGB_601_STANDARD, +}; + +static const u32 vmx_rgb_to_blt_yuv888[] = { + B2R2_VMX0_RGB_TO_BLT_YUV888_601_STANDARD, + B2R2_VMX1_RGB_TO_BLT_YUV888_601_STANDARD, + B2R2_VMX2_RGB_TO_BLT_YUV888_601_STANDARD, + B2R2_VMX3_RGB_TO_BLT_YUV888_601_STANDARD, +}; + +static const u32 vmx_blt_yuv888_to_rgb[] = { + B2R2_VMX0_BLT_YUV888_TO_RGB_601_STANDARD, + B2R2_VMX1_BLT_YUV888_TO_RGB_601_STANDARD, + B2R2_VMX2_BLT_YUV888_TO_RGB_601_STANDARD, + B2R2_VMX3_BLT_YUV888_TO_RGB_601_STANDARD, +}; + +static const u32 vmx_rgb_to_yvu[] = { + B2R2_VMX0_RGB_TO_YVU_601_STANDARD, + B2R2_VMX1_RGB_TO_YVU_601_STANDARD, + B2R2_VMX2_RGB_TO_YVU_601_STANDARD, + B2R2_VMX3_RGB_TO_YVU_601_STANDARD, +}; + +static const u32 vmx_yvu_to_rgb[] = { + B2R2_VMX0_YVU_TO_RGB_601_STANDARD, + B2R2_VMX1_YVU_TO_RGB_601_STANDARD, + B2R2_VMX2_YVU_TO_RGB_601_STANDARD, + B2R2_VMX3_YVU_TO_RGB_601_STANDARD, +}; + +static const u32 vmx_bgr_to_yuv[] = { + B2R2_VMX0_BGR_TO_YUV_601_STANDARD, + B2R2_VMX1_BGR_TO_YUV_601_STANDARD, + B2R2_VMX2_BGR_TO_YUV_601_STANDARD, + B2R2_VMX3_BGR_TO_YUV_601_STANDARD, +}; + +static const u32 vmx_yuv_to_bgr[] = { + B2R2_VMX0_YUV_TO_BGR_601_STANDARD, + B2R2_VMX1_YUV_TO_BGR_601_STANDARD, + B2R2_VMX2_YUV_TO_BGR_601_STANDARD, + B2R2_VMX3_YUV_TO_BGR_601_STANDARD, +}; + +static const u32 vmx_bgr_to_yvu[] = { + B2R2_VMX0_BGR_TO_YVU_601_STANDARD, + B2R2_VMX1_BGR_TO_YVU_601_STANDARD, + B2R2_VMX2_BGR_TO_YVU_601_STANDARD, + B2R2_VMX3_BGR_TO_YVU_601_STANDARD, +}; + +static const u32 vmx_yvu_to_bgr[] = { + B2R2_VMX0_YVU_TO_BGR_601_STANDARD, + B2R2_VMX1_YVU_TO_BGR_601_STANDARD, + B2R2_VMX2_YVU_TO_BGR_601_STANDARD, + B2R2_VMX3_YVU_TO_BGR_601_STANDARD, +}; + +/** + * VMx values for color space conversions + * (full range conversions) + */ + +static const u32 vmx_full_rgb_to_yuv[] = { + B2R2_VMX0_RGB_TO_YUV_601_FULL_RANGE, + B2R2_VMX1_RGB_TO_YUV_601_FULL_RANGE, + B2R2_VMX2_RGB_TO_YUV_601_FULL_RANGE, + B2R2_VMX3_RGB_TO_YUV_601_FULL_RANGE, +}; + +static const u32 vmx_full_yuv_to_rgb[] = { + B2R2_VMX0_YUV_TO_RGB_601_FULL_RANGE, + B2R2_VMX1_YUV_TO_RGB_601_FULL_RANGE, + B2R2_VMX2_YUV_TO_RGB_601_FULL_RANGE, + B2R2_VMX3_YUV_TO_RGB_601_FULL_RANGE, +}; + +static const u32 vmx_full_rgb_to_blt_yuv888[] = { + B2R2_VMX0_RGB_TO_BLT_YUV888_601_FULL_RANGE, + B2R2_VMX1_RGB_TO_BLT_YUV888_601_FULL_RANGE, + B2R2_VMX2_RGB_TO_BLT_YUV888_601_FULL_RANGE, + B2R2_VMX3_RGB_TO_BLT_YUV888_601_FULL_RANGE, +}; + +static const u32 vmx_full_blt_yuv888_to_rgb[] = { + B2R2_VMX0_BLT_YUV888_TO_RGB_601_FULL_RANGE, + B2R2_VMX1_BLT_YUV888_TO_RGB_601_FULL_RANGE, + B2R2_VMX2_BLT_YUV888_TO_RGB_601_FULL_RANGE, + B2R2_VMX3_BLT_YUV888_TO_RGB_601_FULL_RANGE, +}; + +static const u32 vmx_full_yvu_to_rgb[] = { + B2R2_VMX0_YVU_TO_RGB_601_FULL_RANGE, + B2R2_VMX1_YVU_TO_RGB_601_FULL_RANGE, + B2R2_VMX2_YVU_TO_RGB_601_FULL_RANGE, + B2R2_VMX3_YVU_TO_RGB_601_FULL_RANGE, +}; + +static const u32 vmx_full_rgb_to_yvu[] = { + B2R2_VMX0_RGB_TO_YVU_601_FULL_RANGE, + B2R2_VMX1_RGB_TO_YVU_601_FULL_RANGE, + B2R2_VMX2_RGB_TO_YVU_601_FULL_RANGE, + B2R2_VMX3_RGB_TO_YVU_601_FULL_RANGE, +}; + +static const u32 vmx_full_bgr_to_yuv[] = { + B2R2_VMX0_BGR_TO_YUV_601_FULL_RANGE, + B2R2_VMX1_BGR_TO_YUV_601_FULL_RANGE, + B2R2_VMX2_BGR_TO_YUV_601_FULL_RANGE, + B2R2_VMX3_BGR_TO_YUV_601_FULL_RANGE, +}; + +static const u32 vmx_full_yuv_to_bgr[] = { + B2R2_VMX0_YUV_TO_BGR_601_FULL_RANGE, + B2R2_VMX1_YUV_TO_BGR_601_FULL_RANGE, + B2R2_VMX2_YUV_TO_BGR_601_FULL_RANGE, + B2R2_VMX3_YUV_TO_BGR_601_FULL_RANGE, +}; + +static const u32 vmx_full_bgr_to_yvu[] = { + B2R2_VMX0_BGR_TO_YVU_601_FULL_RANGE, + B2R2_VMX1_BGR_TO_YVU_601_FULL_RANGE, + B2R2_VMX2_BGR_TO_YVU_601_FULL_RANGE, + B2R2_VMX3_BGR_TO_YVU_601_FULL_RANGE, +}; + +static const u32 vmx_full_yvu_to_bgr[] = { + B2R2_VMX0_YVU_TO_BGR_601_FULL_RANGE, + B2R2_VMX1_YVU_TO_BGR_601_FULL_RANGE, + B2R2_VMX2_YVU_TO_BGR_601_FULL_RANGE, + B2R2_VMX3_YVU_TO_BGR_601_FULL_RANGE, +}; + +/* + * Forward declaration of private functions + */ + +/* + * Public functions + */ + +/** + * Setup input versatile matrix for color space conversion + */ +int b2r2_setup_ivmx(struct b2r2_node *node, enum b2r2_color_conversion cc) +{ + const u32 *vmx = NULL; + + if (b2r2_get_vmx(cc, &vmx) < 0 || vmx == NULL) + return -1; + + node->node.GROUP0.B2R2_INS |= B2R2_INS_IVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_IVMX; + + node->node.GROUP15.B2R2_VMX0 = vmx[0]; + node->node.GROUP15.B2R2_VMX1 = vmx[1]; + node->node.GROUP15.B2R2_VMX2 = vmx[2]; + node->node.GROUP15.B2R2_VMX3 = vmx[3]; + + return 0; +} + +/** + * Setup output versatile matrix for color space conversion + */ +int b2r2_setup_ovmx(struct b2r2_node *node, enum b2r2_color_conversion cc) +{ + const u32 *vmx = NULL; + + if (b2r2_get_vmx(cc, &vmx) < 0 || vmx == NULL) + return -1; + + node->node.GROUP0.B2R2_INS |= B2R2_INS_OVMX_ENABLED; + node->node.GROUP0.B2R2_CIC |= B2R2_CIC_OVMX; + + node->node.GROUP16.B2R2_VMX0 = vmx[0]; + node->node.GROUP16.B2R2_VMX1 = vmx[1]; + node->node.GROUP16.B2R2_VMX2 = vmx[2]; + node->node.GROUP16.B2R2_VMX3 = vmx[3]; + + return 0; +} + +enum b2r2_color_conversion b2r2_get_color_conversion(enum b2r2_blt_fmt src_fmt, + enum b2r2_blt_fmt dst_fmt, bool fullrange) +{ + if (b2r2_is_rgb_fmt(src_fmt)) { + if (b2r2_is_yvu_fmt(dst_fmt)) + return fullrange ? B2R2_CC_RGB_TO_YVU_FULL : + B2R2_CC_RGB_TO_YVU; + 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. + */ + return fullrange ? B2R2_CC_RGB_TO_BLT_YUV888_FULL : + B2R2_CC_RGB_TO_BLT_YUV888; + else if (b2r2_is_yuv_fmt(dst_fmt)) + return fullrange ? B2R2_CC_RGB_TO_YUV_FULL : + B2R2_CC_RGB_TO_YUV; + else if (b2r2_is_bgr_fmt(dst_fmt)) + return B2R2_CC_RGB_TO_BGR; + } else if (b2r2_is_yvu_fmt(src_fmt)) { + if (b2r2_is_rgb_fmt(dst_fmt)) + return fullrange ? B2R2_CC_YVU_FULL_TO_RGB : + B2R2_CC_YVU_TO_RGB; + else if (b2r2_is_bgr_fmt(dst_fmt)) + return fullrange ? B2R2_CC_YVU_FULL_TO_BGR : + B2R2_CC_YVU_TO_BGR; + 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 B2R2_CC_YVU_TO_BLT_YUV888; + else if (b2r2_is_yuv_fmt(dst_fmt) && + !b2r2_is_yvu_fmt(dst_fmt)) + return B2R2_CC_YVU_TO_YUV; + } 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 (b2r2_is_rgb_fmt(dst_fmt)) + return fullrange ? B2R2_CC_BLT_YUV888_FULL_TO_RGB : + B2R2_CC_BLT_YUV888_TO_RGB; + else if (b2r2_is_yvu_fmt(dst_fmt)) + return B2R2_CC_BLT_YUV888_TO_YVU; + else if (b2r2_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: + return B2R2_CC_NOTHING; + default: + return B2R2_CC_BLT_YUV888_TO_YUV; + } + } + } else if (b2r2_is_yuv_fmt(src_fmt)) { + if (b2r2_is_rgb_fmt(dst_fmt)) + return fullrange ? B2R2_CC_YUV_FULL_TO_RGB : + B2R2_CC_YUV_TO_RGB; + else if (b2r2_is_bgr_fmt(dst_fmt)) + return fullrange ? B2R2_CC_YUV_FULL_TO_BGR : + B2R2_CC_YUV_TO_BGR; + 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 B2R2_CC_YUV_TO_BLT_YUV888; + else if (b2r2_is_yvu_fmt(dst_fmt)) + return B2R2_CC_YVU_TO_YUV; + } else if (b2r2_is_bgr_fmt(src_fmt)) { + if (b2r2_is_rgb_fmt(dst_fmt)) + return B2R2_CC_RGB_TO_BGR; + else if (b2r2_is_yvu_fmt(dst_fmt)) + return fullrange ? B2R2_CC_BGR_TO_YVU_FULL : + B2R2_CC_BGR_TO_YVU; + 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 (b2r2_is_yuv_fmt(dst_fmt)) + return fullrange ? B2R2_CC_BGR_TO_YUV_FULL : + B2R2_CC_BGR_TO_YUV; + } + + return B2R2_CC_NOTHING; +} + +int b2r2_get_vmx(enum b2r2_color_conversion cc, const u32 **vmx) +{ + if (vmx == NULL) + return -1; + + switch (cc) { + case B2R2_CC_RGB_TO_BGR: + *vmx = &vmx_rgb_to_bgr[0]; + break; + case B2R2_CC_BLT_YUV888_TO_YVU: + *vmx = &vmx_blt_yuv888_to_yvu[0]; + break; + case B2R2_CC_BLT_YUV888_TO_YUV: + *vmx = &vmx_blt_yuv888_to_yuv[0]; + break; + case B2R2_CC_YVU_TO_YUV: + *vmx = &vmx_yvu_to_yuv[0]; + break; + case B2R2_CC_YVU_TO_BLT_YUV888: + *vmx = &vmx_yvu_to_blt_yuv888[0]; + break; + case B2R2_CC_YUV_TO_BLT_YUV888: + *vmx = &vmx_yuv_to_blt_yuv888[0]; + break; + case B2R2_CC_RGB_TO_YUV: + *vmx = &vmx_rgb_to_yuv[0]; + break; + case B2R2_CC_RGB_TO_YUV_FULL: + *vmx = &vmx_full_rgb_to_yuv[0]; + break; + case B2R2_CC_RGB_TO_YVU: + *vmx = &vmx_rgb_to_yvu[0]; + break; + case B2R2_CC_RGB_TO_YVU_FULL: + *vmx = &vmx_full_rgb_to_yvu[0]; + break; + case B2R2_CC_RGB_TO_BLT_YUV888: + *vmx = &vmx_rgb_to_blt_yuv888[0]; + break; + case B2R2_CC_RGB_TO_BLT_YUV888_FULL: + *vmx = &vmx_full_rgb_to_blt_yuv888[0]; + break; + case B2R2_CC_BGR_TO_YVU: + *vmx = &vmx_bgr_to_yvu[0]; + break; + case B2R2_CC_BGR_TO_YVU_FULL: + *vmx = &vmx_full_bgr_to_yvu[0]; + break; + case B2R2_CC_BGR_TO_YUV: + *vmx = &vmx_bgr_to_yuv[0]; + break; + case B2R2_CC_BGR_TO_YUV_FULL: + *vmx = &vmx_full_bgr_to_yuv[0]; + break; + case B2R2_CC_YUV_TO_RGB: + *vmx = &vmx_yuv_to_rgb[0]; + break; + case B2R2_CC_YUV_FULL_TO_RGB: + *vmx = &vmx_full_yuv_to_rgb[0]; + break; + case B2R2_CC_YUV_TO_BGR: + *vmx = &vmx_yuv_to_bgr[0]; + break; + case B2R2_CC_YUV_FULL_TO_BGR: + *vmx = &vmx_full_yuv_to_bgr[0]; + break; + case B2R2_CC_YVU_TO_RGB: + *vmx = &vmx_yvu_to_rgb[0]; + break; + case B2R2_CC_YVU_FULL_TO_RGB: + *vmx = &vmx_full_yvu_to_rgb[0]; + break; + case B2R2_CC_YVU_TO_BGR: + *vmx = &vmx_yvu_to_bgr[0]; + break; + case B2R2_CC_YVU_FULL_TO_BGR: + *vmx = &vmx_full_yvu_to_bgr[0]; + break; + case B2R2_CC_BLT_YUV888_TO_RGB: + *vmx = &vmx_blt_yuv888_to_rgb[0]; + break; + case B2R2_CC_BLT_YUV888_FULL_TO_RGB: + *vmx = &vmx_full_blt_yuv888_to_rgb[0]; + break; + case B2R2_CC_NOTHING: + default: + break; + } + + return 0; +} + + diff --git a/drivers/video/b2r2/b2r2_hw_convert.h b/drivers/video/b2r2/b2r2_hw_convert.h new file mode 100644 index 00000000000..e173e898e44 --- /dev/null +++ b/drivers/video/b2r2/b2r2_hw_convert.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) ST-Ericsson SA 2012 + * + * ST-Ericsson B2R2 hw color conversion definitions + * + * Author: Jorgen Nilsson <jorgen.nilsson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef B2R2_HW_CONVERT_H__ +#define B2R2_HW_CONVERT_H__ + +#include "b2r2_internal.h" + +enum b2r2_color_conversion { + B2R2_CC_NOTHING = 0, + B2R2_CC_RGB_TO_BGR, + B2R2_CC_BLT_YUV888_TO_YVU, + B2R2_CC_BLT_YUV888_TO_YUV, + B2R2_CC_YUV_TO_BLT_YUV888, + B2R2_CC_YVU_TO_YUV, + B2R2_CC_YVU_TO_BLT_YUV888, + B2R2_CC_RGB_TO_YUV, + B2R2_CC_RGB_TO_YUV_FULL, + B2R2_CC_RGB_TO_YVU, + B2R2_CC_RGB_TO_YVU_FULL, + B2R2_CC_RGB_TO_BLT_YUV888, + B2R2_CC_RGB_TO_BLT_YUV888_FULL, + B2R2_CC_BGR_TO_YVU, + B2R2_CC_BGR_TO_YVU_FULL, + B2R2_CC_BGR_TO_YUV, + B2R2_CC_BGR_TO_YUV_FULL, + B2R2_CC_YUV_TO_RGB, + B2R2_CC_YUV_FULL_TO_RGB, + B2R2_CC_YUV_TO_BGR, + B2R2_CC_YUV_FULL_TO_BGR, + B2R2_CC_YVU_TO_RGB, + B2R2_CC_YVU_FULL_TO_RGB, + B2R2_CC_YVU_TO_BGR, + B2R2_CC_YVU_FULL_TO_BGR, + B2R2_CC_BLT_YUV888_TO_RGB, + B2R2_CC_BLT_YUV888_FULL_TO_RGB, +}; + +int b2r2_setup_ivmx(struct b2r2_node *node, enum b2r2_color_conversion cc); +int b2r2_setup_ovmx(struct b2r2_node *node, enum b2r2_color_conversion cc); +enum b2r2_color_conversion b2r2_get_color_conversion(enum b2r2_blt_fmt src_fmt, + enum b2r2_blt_fmt dst_fmt, bool fullrange); +int b2r2_get_vmx(enum b2r2_color_conversion cc, const u32 **vmx); + +#endif /* B2R2_HW_CONVERT_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..c8eb2f7b025 --- /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 device *dev, + 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 device *dev, + struct b2r2_blt_img *img); +static bool validate_rect(struct device *dev, + 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 device *dev, + 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(dev, + 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 device *dev, + 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(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(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(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(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(dev, img->pitch, img->width, + img->fmt)) { + b2r2_log_info(dev, + "Validation Error: " + "img->pitch != 0 && " + "!is_valid_pitch_for_fmt(dev, " + "img->pitch, img->width, img->fmt)\n"); + return false; + } + } + + if (!is_valid_height_for_fmt(img->width, img->fmt)) { + b2r2_log_info(dev, "Validation Error: " + "!is_valid_height_for_fmt(img->width, img->fmt)\n"); + return false; + } + + img_size = b2r2_get_img_size(dev, 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(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 device *dev, + struct b2r2_blt_rect *rect) +{ + if (rect->width < 0 || rect->height < 0) { + b2r2_log_info(dev, "Validation Error: " + "rect->width < 0 || rect->height < 0\n"); + return false; + } + + return true; +} + +bool b2r2_validate_user_req(struct device *dev, + 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(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(dev, &req->src_rect)) { + b2r2_log_info(dev, "Validation Error: " + "!validate_rect(dev, &req->src_rect)\n"); + return false; + } + } + + if (!validate_rect(dev, &req->dst_rect)) { + b2r2_log_info(dev, "Validation Error: " + "!validate_rect(dev, &req->dst_rect)\n"); + return false; + } + + if (is_bg_img_used) { + if (!validate_rect(dev, &req->bg_rect)) { + b2r2_log_info(dev, "Validation Error: " + "!validate_rect(dev, &req->bg_rect)\n"); + return false; + } + } + + if (is_dst_clip_rect_used) { + if (!validate_rect(dev, &req->dst_clip_rect)) { + b2r2_log_info(dev, "Validation Error: " + "!validate_rect(dev, &req->dst_clip_rect)\n"); + return false; + } + } + + if (is_src_img_used) { + struct b2r2_blt_rect src_img_bounding_rect; + + if (!validate_img(dev, &req->src_img)) { + b2r2_log_info(dev, "Validation Error: " + "!validate_img(dev, &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(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(dev, &req->bg_img)) { + b2r2_log_info(dev, "Validation Error: " + "!validate_img(dev, &req->bg_img)\n"); + return false; + } + + if (!is_valid_bg_format(req->bg_img.fmt)) { + b2r2_log_info(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(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(dev, &req->src_mask)) { + b2r2_log_info(dev, "Validation Error: " + "!validate_img(dev, &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(dev, "Validation Error: " + "!b2r2_is_rect_inside_rect(&req->src_rect, " + "&src_mask_bounding_rect)\n"); + return false; + } + } + + if (!validate_img(dev, &req->dst_img)) { + b2r2_log_info(dev, "Validation Error: " + "!validate_img(dev, &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(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..25f022a45ab --- /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 device *dev, + 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..329d644e5e1 --- /dev/null +++ b/drivers/video/b2r2/b2r2_internal.h @@ -0,0 +1,610 @@ +/* + * 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 2 + +/* 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 + +/* The defined bits of the Interrupt Status Register */ +#define B2R2_ITS_MASK 0x0FFFF0FF + +/** + * 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_control_instance - Represents the B2R2 instance + * (one per open and blitter core) + * + * @lock: Lock to protect the instance + * @control_id: The b2r2 core core control identifier + * @control: The b2r2 core control entity + * + * @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 + */ +struct b2r2_control_instance { + struct mutex lock; + int control_id; + struct b2r2_control *control; + + /* 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_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 + * @rotation - determines if rotation is requested + * @fullrange - determines YUV<->RGB conversion matrix (iVMx) + * @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 fullrange; + + 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 data; + 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 + * @core_mask: Bit mask with the cores doing part of the 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_control_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; + u32 core_mask; + + /* 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 +}; + +/** + * + * @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 device *dev; + void *data; + int id; + struct kref ref; + bool enabled; + 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); + +/** + * b2r2_blt_add_control() - Add the b2r2 core control + */ +void b2r2_blt_add_control(struct b2r2_control *cont); + +/** + * b2r2_blt_remove_control() - Remove the b2r2 core control + */ +void b2r2_blt_remove_control(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..584b324b8fe --- /dev/null +++ b/drivers/video/b2r2/b2r2_mem_alloc.c @@ -0,0 +1,669 @@ +/* + * 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 (!IS_ERR_OR_NULL(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); + mem_block->debugfs_block = NULL; + } + + /* 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 (!IS_ERR_OR_NULL(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 (!IS_ERR_OR_NULL(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..b2fb07580ca --- /dev/null +++ b/drivers/video/b2r2/b2r2_node_split.c @@ -0,0 +1,3033 @@ +/* + * 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_convert.h" +#include "b2r2_filters.h" +#include "b2r2_utils.h" + +#include <linux/kernel.h> + +/* + * Macros and constants + */ + +#define INSTANCES_DEFAULT_SIZE 10 +#define INSTANCES_GROW_SIZE 5 + +/* + * Internal types + */ + + +/* + * Global variables + */ + + +/* + * 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, + bool fullrange); +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 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 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 (b2r2_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 (b2r2_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) && + (b2r2_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; + + /* 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 && b2r2_fmt_has_alpha(this->dst.fmt)) || + b2r2_fmt_has_alpha(this->src.fmt); + else if (this->flags & B2R2_BLT_FLAG_BG_BLEND) + this->blend = true; + + /* Check for full range YUV conversion */ + if (this->flags & B2R2_BLT_FLAG_FULL_RANGE_YUV) + this->fullrange = 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 && + b2r2_is_yuv_fmt(this->src.fmt); + downsample = this->dst.type != B2R2_FMT_TYPE_RASTER && + b2r2_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; +} + +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 (b2r2_is_rgb_fmt(bg_fmt)) { + if (b2r2_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 (b2r2_is_yuv_fmt(dst_fmt)) + return true; + else if (b2r2_is_bgr_fmt(dst_fmt)) + return true; + } else if (b2r2_is_yvu_fmt(bg_fmt)) { + if (b2r2_is_rgb_fmt(dst_fmt)) + return true; + else if (b2r2_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 (b2r2_is_yuv_fmt(dst_fmt) && + !b2r2_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 (b2r2_is_rgb_fmt(dst_fmt)) { + return true; + } else if (b2r2_is_yvu_fmt(dst_fmt)) { + return true; + } else if (b2r2_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 (b2r2_is_yuv_fmt(bg_fmt)) { + if (b2r2_is_rgb_fmt(dst_fmt)) + return true; + else if (b2r2_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 (b2r2_is_yvu_fmt(dst_fmt)) + return true; + } else if (b2r2_is_bgr_fmt(bg_fmt)) { + if (b2r2_is_rgb_fmt(dst_fmt)) + return true; + else if (b2r2_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 (b2r2_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, bool fullrange) +{ + enum b2r2_color_conversion cc = + b2r2_get_color_conversion(src->fmt, dst->fmt, fullrange); + + b2r2_get_vmx(cc, vmx); + + 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 (b2r2_is_yuv_fmt(this->dst.fmt)) { + this->src.fmt = B2R2_BLT_FMT_32_BIT_AYUV8888; + } else if (b2r2_is_rgb_fmt(this->dst.fmt)) { + this->src.fmt = B2R2_BLT_FMT_32_BIT_ARGB8888; + } else if (b2r2_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) && b2r2_fmt_has_alpha(this->src.fmt)) { + u8 pixel_alpha = b2r2_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 = b2r2_set_alpha(this->src.fmt, 0xFF, + this->src.color); + } + + ret = analyze_fmt_conv( + cont, &this->src, &this->dst, &this->ivmx, + node_count, this->fullrange); + 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, this->fullrange); + 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, + this->fullrange); + 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, + this->fullrange); + 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, this->fullrange); + 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, this->fullrange); + 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 (b2r2_is_yuv_fmt(this->dst.fmt)) + tmp_fmt = B2R2_BLT_FMT_32_BIT_AYUV8888; + else if (b2r2_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->dev, this->src.rect.width, + this->dst.rect.height, &hsf); + if (ret < 0) + goto error; + + ret = calculate_scale_factor(cont->dev, this->src.rect.height, + this->dst.rect.width, &vsf); + if (ret < 0) + goto error; + } else { + ret = calculate_scale_factor(cont->dev, this->src.rect.width, + this->dst.rect.width, &hsf); + if (ret < 0) + goto error; + + ret = calculate_scale_factor(cont->dev, 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 = b2r2_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 = b2r2_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 = b2r2_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 && !b2r2_is_yuv444_fmt(src->fmt); + if (upsample) { + h_rsf /= 2; + + if (b2r2_is_yuv420_fmt(src->fmt)) + v_rsf /= 2; + } + + /* Check for downsampling of chroma */ + downsample = !dst_raster && !b2r2_is_yuv444_fmt(dst->fmt); + if (downsample) { + h_rsf *= 2; + + if (b2r2_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 (!b2r2_is_yuv444_fmt(src->fmt)) { + tmp_buf.win.x >>= 1; + tmp_buf.win.width = (tmp_buf.win.width + 1) / 2; + + if (b2r2_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 (!b2r2_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 (b2r2_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 (!b2r2_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 (b2r2_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 (!b2r2_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 = b2r2_get_fmt_type(img->fmt); + + if (color_fill) { + buf->type = B2R2_FMT_TYPE_RASTER; + buf->color = color; + } else { + buf->addr = addr; + + buf->alpha_range = b2r2_get_alpha_range(img->fmt); + + if (img->pitch == 0) + buf->pitch = b2r2_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 (b2r2_is_yuv422_fmt(buf->fmt) || + b2r2_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 (b2r2_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 (b2r2_is_yuv422_fmt(buf->fmt)) { + buf->chroma_cr_addr = + (u32)(((u8 *)buf->chroma_addr) + + (buf->pitch >> 1) * buf->height); + } else if (b2r2_is_yvu420_fmt(buf->fmt)) { + buf->chroma_addr = + (u32)(((u8 *)buf->chroma_cr_addr) + + (buf->pitch >> 1) * + ((buf->height + 1) >> 1)); + } else if (b2r2_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 (b2r2_is_rgb_fmt(pref_fmt)) { + fmt = B2R2_BLT_FMT_32_BIT_ARGB8888; + } else if (b2r2_is_bgr_fmt(pref_fmt)) { + fmt = B2R2_BLT_FMT_32_BIT_ABGR8888; + } else if (b2r2_is_yvu_fmt(pref_fmt)) { + fmt = B2R2_BLT_FMT_CB_Y_CR_Y; + } else if (b2r2_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 = b2r2_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, (u32) B2R2_RESCALE_MAX_WIDTH); + pitch = b2r2_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; + +} + +/** + * 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 | b2r2_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, (s32) buf->width) - 1; + t = max(t, 0); + b = min(b, (s32) 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 | b2r2_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 | b2r2_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..cb95af9380e --- /dev/null +++ b/drivers/video/b2r2/b2r2_profiler_socket.c @@ -0,0 +1,107 @@ +/* + * 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" +#include "b2r2_core.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_core *core = (struct b2r2_core *) request->job.data; + struct b2r2_control *cont = core->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..44c738b5aab --- /dev/null +++ b/drivers/video/b2r2/b2r2_utils.c @@ -0,0 +1,1324 @@ +/* + * 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 device *dev, + u32 from, u32 to, u16 *sf_out) +{ + int ret; + u32 sf; + + b2r2_log_info(dev, "%s\n", __func__); + + if (to == from) { + *sf_out = 1 << 10; + return 0; + } else if (to == 0) { + b2r2_log_err(dev, "%s: To is 0!\n", __func__); + BUG_ON(1); + } + + sf = (from << 10) / to; + + if ((sf & 0xffff0000) != 0) { + /* Overflow error */ + b2r2_log_warn(dev, "%s: " + "Scale factor too large\n", __func__); + ret = -EINVAL; + goto error; + } else if (sf == 0) { + b2r2_log_warn(dev, "%s: " + "Scale factor too small\n", __func__); + ret = -EINVAL; + goto error; + } + + *sf_out = (u16)sf; + + b2r2_log_info(dev, "%s exit\n", __func__); + + return 0; + +error: + b2r2_log_warn(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 device *dev, + 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(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(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(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(dev, 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(dev, 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(dev, old_src_rect->width, + old_dst_rect->width, &hsf); + if (res < 0) + goto keep_rects; + + res = calculate_scale_factor(dev, 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(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(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(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(dev, "%s original rectangles preserved.\n", __func__); + return; +} + +int b2r2_get_fmt_bpp(struct device *dev, 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(dev, + "%s: Internal error! Format %#x not recognized.\n", + __func__, fmt); + return 32; + } +} + +int b2r2_get_fmt_y_bpp(struct device *dev, 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(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 device *dev, + 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(dev, 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(dev, fmt), 8); + } else { + b2r2_log_err(dev, "%s: Internal error! " + "Pitchless format supplied.\n", + __func__); + return 0; + } +} + +u32 b2r2_get_img_pitch(struct device *dev, struct b2r2_blt_img *img) +{ + if (img->pitch != 0) + return img->pitch; + else + return b2r2_calc_pitch_from_width(dev, img->width, img->fmt); +} + +s32 b2r2_get_img_size(struct device *dev, struct b2r2_blt_img *img) +{ + if (b2r2_is_single_plane_fmt(img->fmt)) { + return (s32)b2r2_get_img_pitch(dev, 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(dev, 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(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(dev, img->fmt)) / 8; + } else { + b2r2_log_err(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; +} + +/** + * b2r2_get_alpha_range() - returns the alpha range of the given format + */ +enum b2r2_ty b2r2_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 */ + } +} + +/** + * b2r2_get_alpha() - returns the pixel alpha in 0...255 range + */ +u8 b2r2_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; + } +} + +/** + * b2r2_set_alpha() - returns a color value with the alpha component set + */ +u32 b2r2_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; +} + +/** + * b2r2_fmt_has_alpha() - returns whether the given format carries an alpha value + */ +bool b2r2_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; + } +} + +/** + * b2r2_is_rgb_fmt() - returns whether the given format is a rgb format + */ +bool b2r2_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; + } +} + +/** + * b2r2_is_bgr_fmt() - returns whether the given format is a bgr format + */ +bool b2r2_is_bgr_fmt(enum b2r2_blt_fmt fmt) +{ + return (fmt == B2R2_BLT_FMT_32_BIT_ABGR8888); +} + +/** + * b2r2_is_yuv_fmt() - returns whether the given format is a yuv format + */ +bool b2r2_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; + } +} + +/** + * b2r2_is_yvu_fmt() - returns whether the given format is a yvu format + */ +bool b2r2_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; + } +} + +/** + * b2r2_is_yuv420_fmt() - returns whether the given format is a yuv420 format + */ +bool b2r2_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; + } +} + +bool b2r2_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; + } +} + +/** + * b2r2_is_yvu420_fmt() - returns whether the given format is a yvu420 format + */ +bool b2r2_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; + } +} + +bool b2r2_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; + } +} + + +/** + * b2r2_is_yuv444_fmt() - returns whether the given format is a yuv444 format + */ +bool b2r2_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; + } +} + +/** + * b2r2_fmt_byte_pitch() - returns the pitch of a pixmap with the given width + */ +int b2r2_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; + } +} + +/** + * b2r2_to_native_fmt() - returns the native B2R2 format + */ +enum b2r2_native_fmt b2r2_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. + */ +u32 b2r2_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; +} + +/** + * b2r2_get_fmt_type() - returns the type of the given format (raster, planar, etc.) + */ +enum b2r2_fmt_type b2r2_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; + } +} + +#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 + */ +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; +} +#endif + +void b2r2_recalculate_rects(struct device *dev, + 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(dev, + req, &new_bg_rect, &new_dst_rect, &new_src_rect); + + req->dst_rect = new_dst_rect; + req->src_rect = new_src_rect; + if (req->flags & B2R2_BLT_FLAG_BG_BLEND) + req->bg_rect = new_bg_rect; +} diff --git a/drivers/video/b2r2/b2r2_utils.h b/drivers/video/b2r2/b2r2_utils.h new file mode 100644 index 00000000000..081ac1f4848 --- /dev/null +++ b/drivers/video/b2r2/b2r2_utils.h @@ -0,0 +1,89 @@ +/* + * 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 device *dev, + 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 device *dev, + 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 device *dev, enum b2r2_blt_fmt fmt); +int b2r2_get_fmt_y_bpp(struct device *dev, 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 device *dev, + s32 width, enum b2r2_blt_fmt fmt); +u32 b2r2_get_img_pitch(struct device *dev, + struct b2r2_blt_img *img); +s32 b2r2_get_img_size(struct device *dev, + 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); + +enum b2r2_ty b2r2_get_alpha_range(enum b2r2_blt_fmt fmt); +u8 b2r2_get_alpha(enum b2r2_blt_fmt fmt, u32 pixel); +u32 b2r2_set_alpha(enum b2r2_blt_fmt fmt, u8 alpha, u32 color); +bool b2r2_fmt_has_alpha(enum b2r2_blt_fmt fmt); +bool b2r2_is_rgb_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_bgr_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_yuv_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_yvu_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_yuv420_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_yuv422_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_yvu420_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_yvu422_fmt(enum b2r2_blt_fmt fmt); +bool b2r2_is_yuv444_fmt(enum b2r2_blt_fmt fmt); +int b2r2_fmt_byte_pitch(enum b2r2_blt_fmt fmt, u32 width); +enum b2r2_native_fmt b2r2_to_native_fmt(enum b2r2_blt_fmt fmt); +u32 b2r2_to_RGB888(u32 color, const enum b2r2_blt_fmt fmt); +enum b2r2_fmt_type b2r2_get_fmt_type(enum b2r2_blt_fmt fmt); +#ifdef CONFIG_DEBUG_FS +int sprintf_req(struct b2r2_blt_request *request, char *buf, int size); +#endif +void b2r2_recalculate_rects(struct device *dev, + struct b2r2_blt_req *req); + +#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..70750998824 --- /dev/null +++ b/drivers/video/mcde/display-av8100.c @@ -0,0 +1,1656 @@ +/* + * 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 <linux/compdev.h> +#include <linux/clonedev.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; +#ifdef CONFIG_COMPDEV + struct mcde_fb *mfb; +#endif + + 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->fbi) { + 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); + +#ifdef CONFIG_COMPDEV + /* TODO need another way for compdev to get actual size */ + mdev->native_x_res = w; + mdev->native_y_res = h; + + mfb = to_mcde_fb(fbi); + /* Create a compdev overlay for this display */ + if (compdev_create(mdev, mfb->ovlys[0], false) < 0) { + dev_warn(&mdev->dev, + "Failed to create compdev for display %s\n", + mdev->name); + } else { + dev_dbg(&mdev->dev, "compdev created for (%s)\n", + mdev->name); + } +#ifdef CONFIG_CLONEDEV + if (clonedev_create()) { + dev_warn(&mdev->dev, + "Failed to create clonedev for display %s\n", + mdev->name); + } else { + dev_dbg(&mdev->dev, "clonedev created for (%s)\n", + mdev->name); + } +#endif +#endif + } else if (!enable && mdev->fbi) { +#ifdef CONFIG_CLONEDEV + clonedev_destroy(); +#endif +#ifdef CONFIG_COMPDEV + compdev_destroy(mdev); +#endif + 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 hdmi_set_rotation(struct mcde_display_device *ddev, + enum mcde_display_rotation rotation) +{ + /* Not possible to rotate HDMI */ + return 0; +} + +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; + dev->set_rotation = hdmi_set_rotation; + + 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..dfbaa4a8765 --- /dev/null +++ b/drivers/video/mcde/display-generic_dsi.c @@ -0,0 +1,307 @@ +/* + * 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__); + 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..900c3f70aa6 --- /dev/null +++ b/drivers/video/mcde/display-samsung_s6d16d0.c @@ -0,0 +1,232 @@ +/* + * 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; + u8 val = 0; + + dev_dbg(&ddev->dev, "Display on s6d16d0\n"); + + ret = mcde_dsi_dcs_write(ddev->chnl_state, + DCS_CMD_SET_TEAR_ON, &val, 1); + if (ret) + dev_warn(&ddev->dev, + "%s:Failed to enable synchronized update\n", __func__); + + 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 = ddev->port->sync_src; + di->port.frame_trig = ddev->port->frame_trig; + 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..867bbb37375 --- /dev/null +++ b/drivers/video/mcde/display-sony_acx424akp_dsi.c @@ -0,0 +1,422 @@ +/* + * 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 SLEEP_IN_DELAY_MS 85 /* Assume 60 Hz 5 frames */ +#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; + u8 val = 0; + + dev_dbg(&ddev->dev, "Display on sony display\n"); + + ret = mcde_dsi_dcs_write(ddev->chnl_state, + DCS_CMD_SET_TEAR_ON, &val, 1); + if (ret) + dev_warn(&ddev->dev, + "%s:Failed to enable synchronized update\n", __func__); + + 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; + + ret = mcde_dsi_dcs_write(ddev->chnl_state, DCS_CMD_ENTER_SLEEP_MODE, + NULL, 0); + /* Wait for 4 frames or more */ + msleep(SLEEP_IN_DELAY_MS); + + return ret; +} + +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; + } + + return mcde_chnl_set_power_mode(ddev->chnl_state, 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 = dev->port->sync_src; + di->port.frame_trig = dev->port->frame_trig; + 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__); + 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..9e9eb78516e --- /dev/null +++ b/drivers/video/mcde/mcde_display.c @@ -0,0 +1,366 @@ +/* + * 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; + u8 param = 0; + enum mcde_display_rotation final; + + final = (360 + rotation - ddev->orientation) % 360; + ret = mcde_chnl_set_rotation(ddev->chnl_state, final); + if (WARN_ON(ret)) + return ret; + + if (final == MCDE_DISPLAY_ROT_180_CW) + param = 0x40; /* Horizontal flip */ + (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_apply_config_default(struct mcde_display_device *ddev) +{ + int 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->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..35a6cbe9540 --- /dev/null +++ b/drivers/video/mcde/mcde_dss.c @@ -0,0 +1,445 @@ +/* + * 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_rotation(ddev, ddev->get_rotation(ddev)); + if (ret < 0) + dev_warn(&ddev->dev, "Failed to set rotation\n"); + + dev_dbg(&ddev->dev, "Display enabled, chnl=%d\n", + ddev->chnl_id); + ddev->enabled = true; + mutex_unlock(&ddev->display_lock); + + return 0; + +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) +{ + u16 x_tmp, y_tmp; + mutex_lock(&ddev->display_lock); + ddev->get_native_resolution(ddev, &x_tmp, &y_tmp); + if (ddev->orientation == MCDE_DISPLAY_ROT_90_CW || + ddev->orientation == MCDE_DISPLAY_ROT_90_CCW) { + *x_res = y_tmp; + *y_res = x_tmp; + } else { + *x_res = x_tmp; + *y_res = y_tmp; + } + 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 __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..92cdb1ef7a9 --- /dev/null +++ b/drivers/video/mcde/mcde_hw.c @@ -0,0 +1,3834 @@ +/* + * 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 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 roten; + u8 rotdir; + u32 rotbuf1; + u32 rotbuf2; + u32 rotbufsize; + + /* 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; + struct mcde_video_mode vmode; + enum mcde_display_rotation rotation; + u32 rotbuf1; + u32 rotbuf2; + u32 rotbufsize; + + 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_reset(u8 link, bool release) +{ + u32 value; + + value = prcmu_read(DB8500_PRCM_DSI_SW_RESET); + if (release) { + switch (link) { + case 0: + value |= DB8500_PRCM_DSI_SW_RESET_DSI0_SW_RESETN; + break; + case 1: + value |= DB8500_PRCM_DSI_SW_RESET_DSI1_SW_RESETN; + break; + case 2: + value |= DB8500_PRCM_DSI_SW_RESET_DSI2_SW_RESETN; + break; + default: + break; + } + } else { + switch (link) { + case 0: + value &= ~DB8500_PRCM_DSI_SW_RESET_DSI0_SW_RESETN; + break; + case 1: + value &= ~DB8500_PRCM_DSI_SW_RESET_DSI1_SW_RESETN; + break; + case 2: + value &= ~DB8500_PRCM_DSI_SW_RESET_DSI2_SW_RESETN; + break; + default: + break; + } + } + prcmu_write(DB8500_PRCM_DSI_SW_RESET, value); +} + +static void dsi_link_switch_byte_clk(u8 link, bool to_system_clock) +{ + u32 value; + + value = prcmu_read(DB8500_PRCM_DSI_GLITCHFREE_EN); + if (to_system_clock) { + switch (link) { + case 0: + value |= DB8500_PRCM_DSI_GLITCHFREE_EN_DSI0_BYTE_CLK; + break; + case 1: + value |= DB8500_PRCM_DSI_GLITCHFREE_EN_DSI1_BYTE_CLK; + break; + case 2: + value |= DB8500_PRCM_DSI_GLITCHFREE_EN_DSI2_BYTE_CLK; + break; + default: + break; + } + } else { + switch (link) { + case 0: + value &= ~DB8500_PRCM_DSI_GLITCHFREE_EN_DSI0_BYTE_CLK; + break; + case 1: + value &= ~DB8500_PRCM_DSI_GLITCHFREE_EN_DSI1_BYTE_CLK; + break; + case 2: + value &= ~DB8500_PRCM_DSI_GLITCHFREE_EN_DSI2_BYTE_CLK; + break; + default: + break; + } + + } + prcmu_write(DB8500_PRCM_DSI_GLITCHFREE_EN, value); + dsi_wfld(link, DSI_MCTL_PLL_CTL, PLL_OUT_SEL, to_system_clock); +} + +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)); + + if (enter_ulpm) { + lane_state = DSI_LANE_STATE_ULPM; + dsi_link_switch_byte_clk(link, true); + } + + 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); + dsi_wfld(link, DSI_MCTL_MAIN_EN, CLKLANE_ULPM_REQ, enter_ulpm); + + if (!enter_ulpm) { + lane_state = DSI_LANE_STATE_IDLE; + dsi_link_switch_byte_clk(link, false); + } + + /* 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_dbg(&mcde_dev->dev, + "Could not enter correct state=%d (link=%d)!\n", + lane_state, link); + break; + } + } + + 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_dbg(&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) { + WARN_ON_ONCE(clk_enable(chnl->clk_dsi_lp)); + WARN_ON_ONCE(clk_enable(chnl->clk_dsi_hs)); + dsi_link_handle_reset(link, true); + } 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); + + 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); + 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); + } +} + +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); + if (chnl->port.frame_trig == MCDE_TRIG_SW) + 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; + } + } + + dsi_link_handle_ulpm(&chnl->port, false); + 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); +} + +static void set_vsync_method(u8 idx, struct mcde_port *port) +{ + u32 out_synch_src = MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_FORMATTER; + u32 src_synch = MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE; + + if (port->type == MCDE_PORTTYPE_DSI) { + switch (port->frame_trig) { + case MCDE_TRIG_HW: + src_synch = MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE; + break; + case MCDE_TRIG_SW: + src_synch = MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE; + break; + default: + src_synch = MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE; + break; + } + + switch (port->sync_src) { + case MCDE_SYNCSRC_OFF: + out_synch_src = + MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_FORMATTER; + break; + case MCDE_SYNCSRC_TE0: + out_synch_src = MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_TE0; + if (src_synch == + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE) { + dev_dbg(&mcde_dev->dev, "%s: badly configured " + "frame sync, TE0 defaulting " + "to hw frame trig\n", __func__); + src_synch = + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE; + } + break; + case MCDE_SYNCSRC_TE1: + out_synch_src = MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_TE1; + if (src_synch == + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE) { + dev_dbg(&mcde_dev->dev, "%s: badly configured " + "frame sync, TE1 defaulting " + "to hw frame trig\n", __func__); + src_synch = + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE; + } + break; + case MCDE_SYNCSRC_BTA: + out_synch_src = + MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_FORMATTER; + break; + case MCDE_SYNCSRC_TE_POLLING: + out_synch_src = + MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_FORMATTER; + if (src_synch == + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE) { + dev_dbg(&mcde_dev->dev, "%s: badly configured " + "frame sync, TE_POLLING defaulting " + "to hw frame trig\n", __func__); + src_synch = + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE; + } + break; + default: + out_synch_src = + MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_FORMATTER; + src_synch = MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE; + dev_dbg(&mcde_dev->dev, "%s: no sync src selected, " + "defaulting to DSI BTA with " + "hw frame trig\n", __func__); + break; + } + } else if (port->type == MCDE_PORTTYPE_DPI) { + out_synch_src = MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC_FORMATTER; + src_synch = port->update_auto_trig ? + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_HARDWARE : + MCDE_CHNL0SYNCHMOD_SRC_SYNCH_SOFTWARE; + } + + mcde_wreg(MCDE_CHNL0SYNCHMOD + + idx * MCDE_CHNL0SYNCHMOD_GROUPOFFSET, + MCDE_CHNL0SYNCHMOD_SRC_SYNCH(src_synch) | + MCDE_CHNL0SYNCHMOD_OUT_SYNCH_SRC(out_synch_src)); +} + +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 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; + } + + set_vsync_method(idx, port); + + 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_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) { + u32 stripwidth; + u32 stripwidth_val; + + /* calc strip width, 32 bits used internally */ + stripwidth = regs->rotbufsize / (video_mode->yres * 4); + if (stripwidth >= 32) + stripwidth_val = MCDE_ROTACONF_STRIP_WIDTH_32PIX; + else if (stripwidth >= 16) + stripwidth_val = MCDE_ROTACONF_STRIP_WIDTH_16PIX; + else if (stripwidth >= 8) + stripwidth_val = MCDE_ROTACONF_STRIP_WIDTH_8PIX; + else if (stripwidth >= 4) + stripwidth_val = MCDE_ROTACONF_STRIP_WIDTH_4PIX; + else + stripwidth_val = MCDE_ROTACONF_STRIP_WIDTH_2PIX; + dev_vdbg(&mcde_dev->dev, "%s stripwidth=%d\n", __func__, + 1 << (stripwidth_val + 1)); + 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(stripwidth_val) | + 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; + struct mcde_platform_data *pdata = mcde_dev->dev.platform_data; + + 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; + chnl->rotbuf1 = pdata->rotbuf1; + chnl->rotbuf2 = pdata->rotbuf2; + chnl->rotbufsize = pdata->rotbufsize; + + _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.roten = roten; + chnl->regs.rotdir = rotdir; + chnl->regs.rotbuf1 = chnl->rotbuf1; + chnl->regs.rotbuf2 = chnl->rotbuf2; + chnl->regs.rotbufsize = chnl->rotbufsize; + 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->port.type == MCDE_PORTTYPE_DSI) { + if (chnl->port.sync_src == MCDE_SYNCSRC_OFF) { + if (chnl->port.frame_trig == MCDE_TRIG_SW) { + do_softwaretrig(chnl); + } else { + enable_flow(chnl); + disable_flow(chnl); + } + dev_vdbg(&mcde_dev->dev, "Channel update (no sync), " + "chnl=%d\n", chnl->id); + } else if (chnl->port.sync_src == MCDE_SYNCSRC_BTA) { + if (chnl->power_mode == MCDE_DISPLAY_PM_ON) { + dsi_te_request(chnl); + } else { + if (chnl->port.frame_trig == MCDE_TRIG_SW) + do_softwaretrig(chnl); + } + if (chnl->port.frame_trig == MCDE_TRIG_HW) { + /* + * During BTA TE the MCDE block will be stalled, + * once the TE is received the DMA trig will + * happen + */ + enable_flow(chnl); + disable_flow(chnl); + } + } + } +} + +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) +{ + dev_vdbg(&mcde_dev->dev, "%s\n", __func__); + + if (!chnl->reserved) + return -EINVAL; + + if ((rotation == MCDE_DISPLAY_ROT_90_CW || + rotation == MCDE_DISPLAY_ROT_90_CCW) && + (chnl->id != MCDE_CHNL_A && chnl->id != MCDE_CHNL_B)) + return -EINVAL; + + chnl->rotation = rotation; + + 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; + } else if (!chnl->regs.roten && chnl->esram_is_enabled) { + WARN_ON_ONCE(regulator_disable(regulator_esram_epod)); + chnl->esram_is_enabled = false; + } + + 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 = false; + 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) diff --git a/firmware/Makefile b/firmware/Makefile index 0d15a3d113a..b74752ef53f 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -32,6 +32,7 @@ fw-shipped-$(CONFIG_ADAPTEC_STARFIRE) += adaptec/starfire_rx.bin \ adaptec/starfire_tx.bin fw-shipped-$(CONFIG_ATARI_DSP56K) += dsp56k/bootstrap.bin fw-shipped-$(CONFIG_ATM_AMBASSADOR) += atmsar11.fw +fw-shipped-$(CONFIG_AV8100) += av8100.fw fw-shipped-$(CONFIG_BNX2X) += bnx2x/bnx2x-e1-6.2.9.0.fw \ bnx2x/bnx2x-e1h-6.2.9.0.fw \ bnx2x/bnx2x-e2-6.2.9.0.fw diff --git a/firmware/av8100.fw.ihex b/firmware/av8100.fw.ihex new file mode 100644 index 00000000000..384a432ea43 --- /dev/null +++ b/firmware/av8100.fw.ihex @@ -0,0 +1,1281 @@ +:1000000080FECBFEA3EE5AF05AF0F8F159EFFDF165 +:1000100045F307F51CF52DF53FF552F557F55CF561 +:1000200061F566F57BF5B5F54CF69DEE9DEE9EEE21 +:10003000000000000000000000000081EAADECAD0F +:1000400038201B7280814D514D514D514D514D51B4 +:100050004D51B420F42A5A9082FECD8000AF7293A5 +:10006000A3205F90808097908D200FAB01A6888998 +:100070009096AD97909AAD8B939EAD9790A2AD80E0 +:10008000B7A6AD81B7AAAD82B7AEAD263120087252 +:1000900082B721A681B7C2A680B701A6B420F52AEF +:1000A0005A908000A77293CCAD492797905D90D469 +:1000B000AD82B7D8AD81B7DCAD80B7E0ADFFAE9013 +:1000C000815929EA265AFB382007724D38201A72C6 +:1000D000490038200572BCFFCD08AEF320792449D1 +:1000E0004424492324490BAD82FECD9E82FECD9F40 +:1000F0005B82FECD80B682FECD81B682FECD82B619 +:1001000082AD9F9086AD859084428C209F9001ABFC +:100110000FA62A31200872FB382007724D38201AAA +:1001200072BCFFCDFB382007723020107231201EC8 +:100130007230201C729505A09E94F6CC5F905F4FA4 +:1001400007382005720C39200572814129382018A2 +:1001500072D5265AFB382007729D9D4D38201A72A1 +:100160004DAEFFCD4DAEFFCD38201B724D4D4D4DE8 +:100170004D382019720425493820187208AE3420F1 +:1001800000000000000000191817161514131211B2 +:10019000100F0E0D0C0B0A090807060504030201D7 +:1001A000000000000000000000000000000000004F +:1001B000000000000000000000000000000000003F +:1001C000000000000000000000000000000000002F +:1001D000000000000000000000000000000000001F +:1001E000000000000000000000000000000000000F +:1001F00000000000000000000000000000000000FF +:1002000000000000000000000000000000000000EE +:1002100000000000000000000000000000000000DE +:1002200000000000000000000000000000000000CE +:1002300000000000000000000000000000000000BE +:1002400000000000000000000000000000000000AE +:10025000000000000000000000000000000000009E +:10026000000000000000000000000000000000008E +:10027000000000000000000000000000000000007E +:10028000000000000000000000000000000000006E +:10029000000000000000000000000000000000005E +:1002A000000000000000000000000000000000004E +:1002B000000000000000000000000000000000003E +:1002C000000000000000000000000000000000002E +:1002D000000000000000000000000000000000001E +:1002E000000000000000000000000000000000000E +:1002F00000000000000000000000000000000000FE +:1003000000000000000000000000000000000000ED +:1003100000000000000000000000000000000000DD +:1003200000000000000000000000000000000000CD +:1003300000000000000000000000000000000000BD +:1003400000000000000000000000000000000000AD +:10035000000000000000000000000000000000009D +:10036000000000000000000000000000000000008D +:10037000000000000000000000000000000000007D +:10038000000000000000000000000000000000006D +:10039000000000000000000000000000000000005D +:1003A000000000000000000000000000000000004D +:1003B00000000000000000008101A60227FBD69289 +:1003C000FC3C0726FBD692FC3C0E26FBD692FC3C5E +:1003D0001726FBD692FC3F81FAB7FBD8925CFAB69F +:1003E000F9B7FBD8925CF9B6F8B7FBD89201AEF832 +:1003F000B6F7B7FBC892F7B6FCBF81FCBE84FAB76C +:10040000FBD6925CF9B7FBD6925CF8B7FBD69201AB +:10041000AEF7B7FBC69288FCBF81FAB7FBDA925CF5 +:10042000FAB6F9B7FBDA925CF9B6F8B7FBDA9201E3 +:10043000AEF8B6F7B7FBCA92F7B6FCBFBAFACCC4AF +:10044000FBCD81FCBEE9264AFB003972FB006972D4 +:100450005AFB0069725AFB00687203AEFCBF1B278F +:100460004DBAFACC0FFBCD81F12001ABFBD6920740 +:100470002B5A0A24FBD792FBDB9203AEFCBF81010F +:10048000A60220FFA604240827FBD192FAB6FC3C62 +:100490000926FBD192F9B6FC3C1226FBD192F8B6A4 +:1004A000FC3C2326FBD192F7B6FC3F81FAB7FBD484 +:1004B000925CFAB6F9B7FBD4925CF9B6F8B7FBD404 +:1004C0009201AEF8B6F7B7FBC492F7B6FCBF81F75E +:1004D000B7FBC992F7B6F8B7FBD9925AF8B6F9B795 +:1004E000FBD9925AF9B6FAB7FBDB92FAB603AEFC27 +:1004F000BF81F73C0224F8B7F8B99FF9B7F9BB42BE +:10050000930F274D8400FBCDFFB60527FEBEFAB73B +:10051000F9BF4293FFB6F8B7F7BF42FEB689FFB7FF +:1005200081F73FF83FF9BFFAB781FCBE84FBD79251 +:10053000FAB65CFBD792F9B65CFBD792F8B601AE7F +:10054000FBC792F7B688FCBF81FCBEFBD792FAB618 +:100550005CFBD792F9B65CFBD792F8B601AEFBC74D +:1005600092F7B6FCBF8101A60227036D0426026D37 +:100570000826016D0E267D81F5264AFA36F936F8F1 +:1005800036F7340B274D8184FAB703E6F9B702E654 +:10059000F8B701E6F7B7F6888101A60227FA3D040D +:1005A00026F93D0826F83D0E26F73D81F5264AF747 +:1005B00039F839F939FA380B274D81F7F7B9F601CF +:1005C000E7F8B901E602E7F9B902E603E7FABB0387 +:1005D000E681F73FF83F81F7B7F8B7FFA6072AF99A +:1005E000BFFAB78141FFBB41529384FFB7FFBB52B3 +:1005F000017BFEBEFFB7529F908881FCBEFAB7FB1D +:10060000D6925CF9B7FBD6925CF8B7FBD69201AEF6 +:10061000F7B7FBC692FCBF81F73FF9B7F8BF5C01A3 +:1006200024F9BB4293F7B6FAB7F9BF4293F7BFE09C +:10063000208FE326017B1A15CD0326B203CAB3032C +:10064000C6DAEDCD032420A11227016B6AF6CDBBDB +:10065000F6CD888155FACDF73FF83FF9B781F9B665 +:10066000FA3FE7FBCDFBB700A94101AB818484844D +:100670008484062008359A1A2010721520C7EEA42B +:100680001520C61420C77CA41420C61320C708A4B4 +:100690001320C609C0CD84848484848484846EDB62 +:1006A000CD47033B48033B49033B4A033B014B8097 +:1006B0004B854B804B1F2729FCCD47AEFB000335F4 +:1006C000B0840035B1840035B2840035B38413356D +:1006D000A4840035A5840035A6840035A7840035A0 +:1006E000A0840035A1840035A2840035A3840035A0 +:1006F0000C8C00350D8C00350E8C00350F8C0035C0 +:10070000188C0035198C00351A8C00351B8C03357C +:10071000048C0035058C0035068C0035078C0A35B5 +:10072000008C0035018C0035028C0035038C0035BF +:100730001C8C00351D8C00351E8C00351F8C04353B +:100740001FC1CDACC3CD248300352583003526835E +:1007500002352783003584840035858400358684FE +:10076000003587842035B4840035B5842035B684BF +:100770000035B784A0350C20B5840035B68400352B +:10078000B78480350E2420A1C803C618840035190B +:100790008400351A8400351B84003578840035794F +:1007A0008400357A8400357B8400353F2001353D57 +:1007B00020C7FFA63C20C706A6470301354803868D +:1007C000354903A0354A03C70F20470302354803C4 +:1007D00049354903F0354A03C71C2048039B354976 +:1007E00003FC354A03C0352A2048038C354903BA37 +:1007F000354A0380353820480324354903F8354A03 +:1008000003C7492047035F7248035F7249035F7261 +:100810004A035F724C2708A03F274A34274A2927FA +:100820004A1F270FA40820C6BE035F72BF03C7017B +:10083000A63E20FE35C80310350A2003A63E202020 +:1008400035C803C721A6113F042023A61100033594 +:100850000827A3F9CD04A494F9CD5B172022A61193 +:100860000001350827A3F9CD02A494F9CD5B2A2015 +:1008700011B730A60627A3F9CD08A494F9CD5B01E2 +:100880006B9484C6026B9584C6036B9684C6046B16 +:100890009784C65A2510A10320C6F22510A1056B26 +:1008A0004CA2034F7205EE72056B4FAD025F72AE44 +:1008B000025F72B8035F7297025F7299025F72986B +:1008C000025F72B3035F72B2035F7276030A357917 +:1008D000035F727A035F7283035F727B035F727CD4 +:1008E000035F727D035F7261035F72BD035F72C25B +:1008F000035F724C035F724D035F7286025F724F3B +:10090000035F7262035F7250035F729B025F729CAF +:10091000025F729D025F724B035F72113F103F4E88 +:10092000035F72A0035F72A1035F72C3035F72C4AF +:1009300003FF35C7035F72BC035F729B06205F72C3 +:1009400088888888888184E3ADF42540A1016B4CB8 +:10095000126F01EE72016B4F888105201072152015 +:100960001172101EADF9CC8BFFA606AE8185017BFE +:100970009AA003C70FA4A003C6A2034F72A0035CF2 +:1009800072016BA203D6A003CE1827A003C1A10356 +:10099000C69B016B4F8881A103C70FA4A103C6A208 +:1009A00003D7A1035C72A103CE808602C75120C683 +:1009B00050201172808590FD0032FC0032FB003225 +:1009C000000132FF0032FE00328484848457F6CD69 +:1009D00063A60520B3035A72B2035A720426B30306 +:1009E000C60F27B203CAB303C67D035F72B2035FAB +:1009F00072B3031835082500A2B203C619A0B303C9 +:100A0000C618207D030135062710A5047B016B1055 +:100A100040C6026B1140C6036B1240C6046B134004 +:100A2000C609C0CD4620C74620C641205F720A4293 +:100A3000200D7288888888FE003BFF003B00013B48 +:100A4000FB003BFC003BFD003B8990808590FD0056 +:100A500032FC0032FB0032000132FF0032FE003275 +:100A600057F6CD152010720727092B10B61220015A +:100A700035FE003BFF003B00013BFB003BFC003B25 +:100A8000FD003B8990800C4000350D4000350E4044 +:100A900000350F400435112080358011204035800D +:100AA0001120203580112010358011200835801745 +:100AB000201472801720157205172005721120046A +:100AC0003580BB03C74A05201A7206201872112010 +:100AD000C702A680BB03C705201A7206201972112F +:100AE00020C701A6800488003505883035068800B7 +:100AF00035078800351020803581B8FACDBCAEFBB3 +:100B000000843581FBB700A94101AB808590FD00D1 +:100B100032FC0032FB0032000132FF0032FE0032B4 +:100B2000FA0032F90032F80032F70032848484840B +:100B30008484B8FACDA0AEFB008435C4FBCD33ADC0 +:100B40005BF73FF83FF91FD7FACDC903CECA03C6FA +:100B5000036B80A4037B046B4F016BA084C6026B04 +:100B6000A184C6036BA284C6046BA384C68484C913 +:100B700003CFCA03C76EC0CD9802CE9902C6CB037D +:100B80003BCC033B0F2052C0CD9802CE9902C6CB7E +:100B9000033BCC033B112405E272CB03C606E07293 +:100BA000CC03C61F2405E2729802C606E0729902C1 +:100BB000C61C25CB03C2057BCC03C0067B0C249846 +:100BC00002C2057B9902C0067B5C20C903CF980254 +:100BD000CECA039902550D264C03C60D20CB03CE79 +:100BE000CA03C7CC03C60B274A4B03C607200135EF +:100BF00007200335082604A105201D7205201C725C +:100C0000082502A19702C61B269802C1057B222651 +:100C10009902C1067B29264A4B03C6CB035F72CCDF +:100C200003C706A6FDF4CDF9B718AAF9B6E7FBCDC0 +:100C3000F5F4CD5B12200AA6FDF4CDF918E7FBCD43 +:100C4000F5F4CD5B102400A2057B0AA0067B1A25D3 +:100C500000A2057B06A0067B036BC7A4037B016B88 +:100C6000BC84C6026BBD84C6036BBE84C6046BBF66 +:100C700084C657274C03C6066BA783C6056BA6839D +:100C8000C6CA035F72C9035F72CC035F72CB035F96 +:100C90007210204035888888888888F7003BF800E3 +:100CA0003BF9003BFA003BFE003BFF003B00013BF1 +:100CB000FB003BFC003BFD003B89908148830035F5 +:100CC000498300354A8300354B830F35808590FD7D +:100CD0000032FC0032FB0032000132FF0032FE0025 +:100CE0003284848484BC035F725DC7CD20AD052649 +:100CF0004ABC03C60B2603A14B03C6C4035C7204A3 +:100D0000270FA1C403C60B20BB0301351126C40362 +:100D10005A721727C403C6112603EA72047B0727F9 +:100D20004C037B05264C047B1127037B04264A04D5 +:100D30007B7DDECD03EE729F036B04EF7203E272E4 +:100D40004104E0725F01A6036B01E272037B046B56 +:100D500002E072047B0E2403E2729F04E0724654A8 +:100D600001EF72026B46542903CE2A03C6082029DC +:100D700003CE2A03C608264A2203C6E32603E172ED +:100D8000A683C6EB2604E172A783C6046BA783C6BD +:100D9000036BA683C605F3CC848484848B0235352B +:100DA0008C0286358D0237358E02BD35C4030F3572 +:100DB000C703013534F3CD8AC0CD8F023B90023B8F +:100DC00091023B92023B3126C703C62BC7CD0327B6 +:100DD000C403C61BF3CC032602A1BA03C605F3CC99 +:100DE000032702A14B03C61020203588888888FE7F +:100DF000003BFF003B00013BFB003BFC003BFD00D8 +:100E00003B8990801020083581E7FBCDFBB700A916 +:100E10004102AB808590FD0032FC0032FB003200C5 +:100E20000132FF0032FE0032FA0032F90032F800DF +:100E300032F700328484848484B8FACDFBBF84AE58 +:100E4000FA1A2FAD5B092004AEFB004435F73F3C96 +:100E5000AD5B026B0884C6036B0984C6046B0A840D +:100E6000C6056B0B84C6B8FACDFBBF84AEFA1B5C1B +:100E7000AD5B2D274D03C632279D02C6026B8484CD +:100E8000C6036B8584C6046B8684C6056B8784C6DF +:100E9000848484E8C8CD4102A941AFAB5F5221AE42 +:100EA000AD02C6024B104B004BAD025C720420AD8C +:100EB000025F720626FFB1FFBF900D26FEB3FE3F14 +:100EC000AD02CE904A5A01264D5F3A2502A1AE02EC +:100ED000C6EBC6CDBB035F7207264ABB03C6062618 +:100EE00004A14603C607264A4B03C6CFD5CDBD0392 +:100EF000C706264ABD03C661035C7204274C610322 +:100F0000C60A2061035F720627C403C6C5035C726C +:100F10000424FFA1C503C6BC030135B8FACDA0AEB9 +:100F2000FB008435F71FEDF1CD5B026BA084C60397 +:100F30006BA184C6046BA284C6056BA384C684849B +:100F400084848AC0CD8F023B90023B91023B920287 +:100F50003BC7035F72412504A1C503C665274A4B01 +:100F600003C6B8FACD9CAEFB008335F7B7F8B7F9E6 +:100F7000B74FFAB7016B9F83C60520147210200685 +:100F8000358888888888F7003BF8003BF9003BFAF1 +:100F9000003BFE003BFF003B00013BFB003BFC0035 +:100FA0003BFD003B899081FB008C35F7B7F8B7F922 +:100FB000B74FFAB7808590FD0032FC0032FB00325B +:100FC000000132FF0032FE0032FA0032F90032F83E +:100FD0000032F7003284B8FACD0CAE27ADF0A40190 +:100FE0007B62035F72052016720620C705AA0620E1 +:100FF000C61B2704A5017BB8FACD0CAE48ADF0A402 +:101000000520167206201472112062035A7247EFEF +:10101000CD02A605264A05204F032502A16203C67C +:10102000B8FACD10AE71AD6303D622276203CE5954 +:10103000270FA5017BB8FACD0CAE4CF0CD0FA4055F +:10104000201672062012724F030135182720A501C1 +:101050007B98AD4F052780A5017B5103D7178CC620 +:1010600050035C725003CE0F2780A507205003CF9A +:1010700006201372092710A520264F03CE016B0FFF +:101080008CC61020103588F7003BF8003BF9003B78 +:10109000FA003BFE003BFF003B00013BFB003BFC3A +:1010A000003BFD003B8990B8FACC0CAEFB008C35C0 +:1010B000F7B7F8B7F9B74FFAB7808590FD0032FC63 +:1010C0000032FB0032000132FF0032FE0032848425 +:1010D0008484A084C7017BA184C7027BA284C70348 +:1010E0007BA384C7047BBC030135016B7FA4017B18 +:1010F0000A20016B80AA017B122702A1BA03C60F46 +:101100002603A1042702A14B03C61A274C03C605D8 +:10111000264D03C6016BA084C6026BA184C6036B77 +:10112000A284C6046BA384C6C5035F72BA03C70357 +:10113000A48384C61FC1CD03264AB903C605201265 +:10114000721020013588888888FE003BFF003B0034 +:10115000013BFB003BFC003BFD003B8990801220E3 +:101160001035808113000135042712B7C084C6A74B +:10117000F6CD11B71EEDCDA7F6CC11B701A6072409 +:1011800020A1C803C609206CEBCDD6206CEBCD05A1 +:101190002604A112B6062702A112B6112602A11139 +:1011A000B6B32057EBCD2A209CEACD2F2017EACDED +:1011B000C22011B717EACD072602A111B68112008D +:1011C000184D551300194D5514001A4D5515001B97 +:1011D0004D556E2520A1C803C6A7F6CD11B7C9E7A6 +:1011E000CD65202BE7CD6A2049E4CD9CF6CC8CE37D +:1011F000CD7520ADE3CD7A20B4E2CD84EECC5EE2B5 +:10120000CD84EECC1EE2CD84EECC71E1CD84EECC6B +:1012100047E0CD8188BCEDD688BDEDD658979CEED1 +:10122000CC03250FA14A7BEE5FEE5AEE55EE43EE5E +:101230001FEE1AEE15EE0FEE0AEE05EEFFEDF9EDDC +:10124000F3EDEDED81E7FBCDFBB700A94102ABF675 +:101250002001A6818585858585062611BE04204F3F +:1012600026C0CD0AA69A7884C7027B7984C7037BFF +:101270007A84C7047B7B84C7057BB8FACD78AEFB44 +:10128000008435F71836AD5B026B7884C6036B7942 +:1012900084C6046B7A84C6056B7B84C656C8CD01B0 +:1012A000A656C8CD4F9B492701E4724F01204C033D +:1012B000264A11B6016B4F012001A6042655FACD2E +:1012C000F83FF93FFA3F77AD5B026BC084C6036B12 +:1012D000C184C6046BC284C6056BC384C688888873 +:1012E000888881B8FACDB4AEFB00843581E7FBCDA8 +:1012F000FBB700A94101AB818585858585057BB854 +:10130000030135042702A111B60A264A13B6056B5C +:1013100001A6042012009803550920D2C8CD052744 +:1013200085854D2F1ECD13BE14B6014B004B1E20DC +:10133000850A1FCD13BE14B6014B9803C715B621FD +:101340002033274D721FCD39209A5EADF91857AD65 +:101350005B9B016BB484C6026BB584C6036BB68419 +:10136000C6046BB784C626C0CDFAA69A1884003589 +:10137000198403351A8483351B84003514450035E0 +:1013800015450035164500351745023514EDCDF9E4 +:1013900016FA1209EDCD5B9B016BB484C6026BB5E6 +:1013A00084C6036BB684C6046BB784C68484848405 +:1013B000848484846EDBCD47033B48033B49033B75 +:1013C0004A033B044BC44BB44B004BEEECCCD2EC89 +:1013D000CC03264AC1ECCC03264AB9ECCC03264AFE +:1013E00015274A12B6EEECCC032702A111B6F2EC97 +:1013F000CCBC03C74C9AB8FACD18AEFB008435F7C5 +:10140000B7F8B7F9B74FFAB712B69BF2ECCC03278F +:1014100003A14B03C6056B01A6C2035F724B035FBA +:10142000720C274A0F274A12274A15274AC203C6B9 +:10143000C0035F72C10301352320C0035F72C10383 +:10144000C702A602200AA6262006274A05274A0C1C +:10145000274AC203C61D2420A1C803C6C203C77FF2 +:10146000A412B64B03033579264A11B6B8035F724E +:101470009A18840035198400351A8400351B8400BD +:10148000359B4B035F721A2702A111B6056B4F887B +:1014900088888888814FD2C8CC032785854D2F1E28 +:1014A000CD11BE12B6804B004B8185858585854F59 +:1014B000848484E8C8CD00AE11A688047B88047BB0 +:1014C00088017BAE025C72042403A10826AE02C12F +:1014D000047BE22205E17213B6056B4C9F90B202C9 +:1014E000D714E69005E6729705EB725221AE047BA5 +:1014F00015204FB102D713B6B002D712B6AF02D73C +:1015000011B6975221AE432403A1047BE82503A121 +:10151000056B4C057B046B057B042611B1AF02D62D +:10152000975221AE056B4F046BAE02C6036B10A63B +:10153000026B02A67120026B03EF7206A94100AB99 +:10154000594859485948594859484A5A01264D5FFF +:10155000016B0FA411B6222581A111B6016B4F8832 +:101560008888888881858585854F790301357A0348 +:10157000C74C082017B70C267B03C616B7047B019F +:101580006B026B036B4F046B7E03C615B7017B14B4 +:10159000B7027B13B7037B12B7047B016B7F03C6D3 +:1015A000026B8003C6036B8103C6046B8203C61102 +:1015B000B74F01204C03267A03CE502079035F7287 +:1015C0007A03C74C5A2079035F727A035F725C27F3 +:1015D0004A17274A10274A11B678030835042712FC +:1015E0003D78035F728888888881B8FACDB4AEFBF5 +:1015F00000843581E7FBCDFBB700A94101AB811029 +:101600004D0035114D0035124D0035819ACBCD017D +:10161000A61CCACD044800350548003506480035EB +:101620000748003531ADFA1A81858585854F9A7C4A +:1016300003187288031A005589031B00558A031C7E +:1016400000558B031D005584031E005585031F00A4 +:10165000558603200055870321005590031200553D +:101660009103130055920314005593031500558CF4 +:10167000031600558D031700558E031800558F0370 +:10168000190055542628A111B65A207C03C710A46E +:101690007C03C664207C031072062627A111B69B2A +:1016A000FACDFBB748A94144AB5208AE11B668FA6F +:1016B000CD12AE9BFACDFBB748A94140AB5208AE64 +:1016C00011B668FACD16AE1448880355154889033B +:1016D0005516488A035517488B03551048840355FF +:1016E000114885035512488603551348870355D87A +:1016F000E9CDF81B02EACD5B016BB484C6026BB581 +:1017000084C6036BB684C6046BB784C64526113DF8 +:1017100077E9CC032528A111B6D1E9CC0DEACDF8A3 +:101720001B02EACD5B26C0CD0AA6016BB484C602BB +:101730006BB584C6036BB684C6046BB784C67C03E2 +:1017400010726DE9CC032791A111B6F5E9CD134DC7 +:101750000335F5E9CD134D43350C4D1E00550D4DA8 +:101760001F00550E4D2000550F4D210055084D1AF4 +:101770000055094D1B00550A4D1C00550B4D1D0011 +:1017800055044D160055054D170055064D180055CA +:10179000074D190055004D120055014D130055021B +:1017A0004D140055034D150055C42755FACDF73F8C +:1017B000F8B706A4F8B6F93FFA3F02EACD5B016B31 +:1017C000144DC6026B154DC6036B164DC6046B1740 +:1017D0004DC626C0CD0FA6F5E9CD134D0335F5E96D +:1017E000CD134DC3352520026B036B046B4FD8E935 +:1017F000CDF81A02EACD5B016BB484C6026BB584E6 +:10180000C6036BB684C6046BB784C6622680A1117A +:10181000B6F72492A111B6E7E8CC032480A111B653 +:101820009BD3E9CC01A6052420A1C803C60C2580C2 +:10183000A111B68888888881484200354942003520 +:101840004A42003581858585854F9A9DC5CD4D03DA +:1018500001356E14CD03279D02C616AD4B420535EA +:1018600004204B42013506277703C60CC4CDB8FAD5 +:10187000CDB4AEFB008435F916E7FBCDFBB700A96C +:101880004101AB5B016BB484C6026BB584C6036BCC +:10189000B684C6046BB784C6F4DACD502059AD4B7C +:1018A00042053504204B42013506277703C613262F +:1018B0004A4D03C66920CCC4CDACC3CD0826113D2A +:1018C0009B77030135042077035F72062602A1117E +:1018D000B68888888881B8FACD78AEFB00843581D7 +:1018E00018800035198000351A8000358108800085 +:1018F00035098000350A80003581585812BE81E7CD +:10190000FBCDFBB700A94107AB81848B4100A94106 +:1019100009AB5B0A6B4F9ACCC4CD4C035F72BC849D +:101920000035BD840035BE841835BF84003542AD16 +:101930001B808035148000351580003516800035F9 +:10194000178000354BAD0B800035048000350580D5 +:1019500000350680003507800035008000350180A5 +:101960000035028000350380003521E7CDFAB7F855 +:10197000A4FAB66AAD5B076B7884C6086B7984C637 +:10198000096B7A84C60A6B7B84C673209DC5CD4CD7 +:101990000301359084C7037B9184C7047B9284C77D +:1019A000057B9384C7067BBEFBCDFBB700A9410333 +:1019B000AB5BF71EF7E6CD5B036BBFA4037B056B48 +:1019C000066B4F0F20F814F7E6CD5B036BBFA40343 +:1019D0007B046BC3A4047B056B066B4F192622A105 +:1019E000C803C69FFBCD10A6FBB700A94103AB5BA4 +:1019F000036B9484C6046B9584C6056B9684C606F7 +:101A00006B9784C682FBCD01A6FBB700A94107AB4B +:101A10005B076B086B4F076B9884C6086B9984C68D +:101A2000096B9A84C60A6B9B84C66DE6CC0325308D +:101A3000A1C803C6CDD9CDBC840035BD840035BE58 +:101A4000841B35BF8440350420BF844135062614ED +:101A50003D14E7CD1B808135B8FACD14AEFB008074 +:101A6000351DFACD5280AE30E4D602E7CD07E7CD82 +:101A70000B8065353080003531800035328000358F +:101A800033808B352C8000352D8000352E8000353D +:101A90002F80093528800035298000352A800035BF +:101AA0002B802A3530264A30E4D602E7CD44810027 +:101AB000354581003546810035478132350C80003F +:101AC000350D8000350E8000350F80083510800000 +:101AD00035118000351280003513800835B8FACDF5 +:101AE0005FFB0080351DFACD06AA4101EA72410272 +:101AF000EA7228AA5240AE2DE4D602E7CD01EF7279 +:101B0000026B5210AE15B6B8FACD04AEFB008035AC +:101B10001DFACD4101EA724102EA7280AA5220AE5A +:101B20002FE4D602E7CD01EF72026B5204AE2EE431 +:101B3000D602E7CD21E7CDFA10FA12FA14F7E6CD76 +:101B40005B076B7884C6086B7984C6096B7A84C698 +:101B50000A6B7B84C6B8FACDB4AEFB008435F916A7 +:101B6000F7E6CD5B076BB484C6086BB584C6096B1A +:101B7000B684C60A6BB784C676E6CC03274A13B68A +:101B80009BEBE6CC01A6052755FACDF73FF83FF9C8 +:101B9000B740A4F9B6FA3FF7E6CD5B076B9484C66D +:101BA000086B9584C6096B9684C60A6B9784C68BAE +:101BB0004100A2410AA05B000200010103010200F2 +:101BC0000200020002010300020102000301000002 +:101BD00003000081854F62035A729A0C8C00350D08 +:101BE0008C00350E8C00350F8C013504200F8C03D2 +:101BF0003506264A6203C6B8FACD10AEFB008C3516 +:101C0000F7B7F8B7F9B74FFA00630355B8FACD1C28 +:101C1000AEFB008C351DFACD5F0FA44E6303C69B4F +:101C20000620C7FAA40620C65227E6256203C6622C +:101C300003C1016B4C9F906303D712E69001E672DB +:101C40009701E072102001A66303C712B66203C7B2 +:101C500011B68881854F4F035F72EF255003C10194 +:101C60006B4C9F14E75103D601EE720A204F13000C +:101C700050035588814F9AA884290055A9842A00C9 +:101C800055AA842B0055AB842C0055B8FACD48AE2C +:101C9000FB0084351DFACD27BE28B6B8FACD44AE78 +:101CA000FB0084351DFACD25BE26B6B8FACD40AE70 +:101CB000FB0084351DFACD23BE24B6B8FACD3CAE68 +:101CC000FB0084351DFACD21BE22B6B8FACD38AE60 +:101CD000FB0084351DFACD1FBE20B6B8FACD34AE58 +:101CE000FB0084351DFACD1DBE1EB6B8FACD30AE50 +:101CF000FB0084351DFACD1BBE1CB6B8FACD2CAE48 +:101D0000FB0084351DFACD19BE1AB6B8FACD28AE3F +:101D1000FB0084351DFACD17BE18B6B8FACD24AE37 +:101D2000FB0084351DFACD15BE16B6B8FACD20AE2F +:101D3000FB0084351DFACD13BE14B6B8FACD1CAE27 +:101D4000FB0084351DFACD11BE12B69B814FBD0339 +:101D500001352003CF1FBE2103C720B61E03CF1DB0 +:101D6000BE1F03C71EB61C03CF1BBE1D03C71CB678 +:101D70001A03CF19BE1B03C71AB61803CF17BE1913 +:101D800003C718B61603CF15BE1703C716B614033C +:101D9000CF13BE1503C714B61203CF11BE1303C76A +:101DA00012B6814F9A30420035314200353242003E +:101DB0003533420035CFD5CD2BD7CD848484848470 +:101DC0008484846EDBCD47033B48033B49033B4A95 +:101DD000033B39033B3A033B3B033B3C033BFED213 +:101DE000CD9B8185858585854F9D0201359A8484AB +:101DF000C7027B8584C7037B8684C7047B8784C72F +:101E00009B056BFBA4057B042004AA057B06270128 +:101E10007B026B8484C6036B8584C6046B8684C690 +:101E2000056B8784C69A6E14CD9B05274D03C600AB +:101E300010CD5A14CD9B02C712B6022004A6042668 +:101E400002A111B69AB8FACDFBBF84AEFA1BE7FB2C +:101E5000CDFBB700A94102AB5B9B056B04AA057BD8 +:101E6000026B8484C6036B8584C6046B8684C605B6 +:101E70006B8784C616000135016B16B69C025F7233 +:101E800004209C0201350627173D888888888881B0 +:101E90008585858585017BBC0301359AB8FACDB46B +:101EA000AEFB008435FA1FE7FBCDFBB700A941026A +:101EB000AB5BB484C7027BB584C7037BB684C7041D +:101EC0007BB784C7057BBEFBCDFBB700A94102AB46 +:101ED0005BFA1EF73FF83FF9B703A4F9B6FA3FE003 +:101EE000FACD5F90FE0001355F12B6046BFCA404CE +:101EF0007B026BB484C6036BB584C6046BB684C620 +:101F0000056BB784C6CC840035CD840035CE844AB9 +:101F100035CF840035102520A1C803C6172603A19C +:101F20004603C665C1CD1CBE20A69B4703220055B3 +:101F3000480323005549032400554A03250055143E +:101F40002789FACD22AE4603C712B6C603C726B606 +:101F500026B69702C721B69802CF1FBE9902C720A6 +:101F6000B64003CF19BE4103C71AB64403CF17BE0C +:101F70004503C718B63E03CF15BE3F03C716B6428A +:101F800003CF13BE4303C714B669E1CCB903C74CF2 +:101F900069E1CC016B01A647274A11274A0D274D5D +:101FA00097025F7299025F7298025F724B03C711CA +:101FB000B6016B4F88888888880000BA420000B854 +:101FC000410AD7233C0000803F818B4100A9411486 +:101FD000AB5B84848484AFC0CD88127B88127B88FD +:101FE000127B88127B0F208AC0CD88127B88127BDF +:101FF00088127B88127B1127C403C6C7035F720453 +:102000002099FBCDFBB700A9410FAB5BE7FBCD8F60 +:10201000AEFB000235162BFFA20D7BFDA00E7B0A46 +:102020002B00A20D7B04A00E6B107B0D6B0F7B0FA2 +:102030006B6020C6106B6120C6116B6220C6126BEC +:102040006320C66820263568202435642087025521 +:102050006520880255662089025567208A025568E6 +:102060002021356420C7057B6520C7067B6620C715 +:10207000077B6720C7087B60208B025561208C029C +:102080005562208D025563208E02558702602055CF +:10209000880261205589026220558A0263205568B2 +:1020A0002021356420C7017B6520C7027B6620C7DD +:1020B000037B6720C7047B8B026420558C0265205C +:1020C000558D026620558E02672055682064356460 +:1020D000208B025565208C025566208D02556720A5 +:1020E0008E0255682021356420C7097B6520C70A08 +:1020F0007B6620C70B7B6720C70C7B68202235B826 +:10210000FACD60AEFB0020351DFACD13EE72147BC4 +:1021100005E0CC032613EA72147BB8FACDFBB700B6 +:10212000A9410FAB5BF73FE7FBCD5FFB008435B800 +:10213000FACDFBB700A94109AB5BE7FBCD37AEFB9E +:1021400000E03506203BAEFB00E03508264C61037D +:10215000C6056B3FE0C6066B40E0C6076B41E0C6B4 +:10216000086B42E0C6016B43E0C6026B44E0C60365 +:102170006B45E0C6046B46E0C68B4100A24112A04D +:102180005B898881F7B7F8B7F9B74FFAB781FBB722 +:1021900000A94101ABE2DDCC03A6E2DDCC02A681C1 +:1021A000204C8184848484B8FACD10AEFB00843541 +:1021B000F81EE7FBCD20AD5B1084C7017B1184C7FF +:1021C000027B1284C7037B1384C7047B026B7FA44A +:1021D000027BB8FACD40AD5BC4FBCDFBB700A94193 +:1021E00007AB5BF7B703A4F7B6F83FF93FFA3FE751 +:1021F000FBCD5DAD5B016B1084C6026B1184C60321 +:102200006B1284C6046B1384C6BEFBCDFBB700A95A +:102210004107AB5B46FACD14A673DECD0B6B04A66B +:1022200066DECC032608A061DECC032604A05EDEB9 +:10223000CC032602A0172702A01B204C1E2006A6B6 +:10224000222002A6262007A60C2710A00C2708A0F3 +:102250000C2704A0342702A03A2702A023240B7BDA +:1022600020A1C803C6076B6020C6086B6120C609A1 +:102270006B6220C60A6B6320C66820263568202161 +:102280003568205235642000356520003566208091 +:1022900035672000359D9D682027356020930255C5 +:1022A000612094025562209502556320960255687C +:1022B00020613568205235B8FACD64AEFB00203578 +:1022C00073DECD0B7B682022356020C7077B612041 +:1022D000C7087B6220C7097B6320C70A7B88888880 +:1022E00088816420003565200035662000358184B2 +:1022F000B8FACD10AEFB008435F9B755AAF9B6FA95 +:10230000B755AAFAB6F8B755AAF8B646FACD18A640 +:10231000F7B7F8B7F9B74FFAB7017BB8FACD14AEF3 +:10232000FB008435F7B73FA4F7B6F83FF93FFA3F13 +:1023300046FACD18A6E7FBCDFBB700A94104AB5B7D +:1023400025240FA1077B26C0CD64A6848484848ABB +:10235000C0CD8F023B90023B91023B92023B0F208B +:10236000AFC0CD8F023B90023B91023B92023B11EA +:10237000264A4B03C614840F351584003516840095 +:102380003517840035046B6020C6056B6120C606D6 +:102390006B6220C6076B6320C66820C74A9D9D6894 +:1023A00020C727A668205235642005356520F535FD +:1023B0006620E13567200035602093025561209446 +:1023C0000255622095025563209602558F026020C7 +:1023D000559002612055910262205592026320556A +:1023E0006820263568202135682052356420003564 +:1023F0006520003566208035672000356820273548 +:1024000093026020559402612055950262205596F2 +:1024100002632055682052356420C7047B6520C7BD +:10242000057B6620C7067B6720C7077B6820C74AF5 +:102430006820C722A66020C7087B6120C7097B628D +:1024400020C70A7B6320C70B7B68205235108402AB +:1024500035118455351284553513845535016B0279 +:10246000A612DDCD67202835092001A612DDCD6733 +:102470002014350B2502A2087BDDA0097B1E204F0E +:1024800012DDCD67200A350A2504A2087BD9A009F0 +:102490007B88812D03CE2E03C6B8FACD818484B803 +:1024A000FACD0CAEFB004135D7FACD412503C94129 +:1024B0002603CB17AD08AEFB004135D7FACD5C0142 +:1024C000264C26AD04AEFB004135D7FACD4123039F +:1024D000C9412403CB4101E2724102E0722B03CED9 +:1024E0002C03C6B8FACD5FFB004135D7FACD5C01AD +:1024F000264C4101E2724102E0722B03CE2C03C64E +:10250000026B3003C6016B2F03C68888813303CE6C +:102510003403C6B8FACD81412F03C9413003CB46FD +:10252000542703CE2803C6812F03CE3003C6B8FA42 +:10253000CD8146FACD10A6D7FACD81FBB700A941CF +:1025400001AB818484848484847C8300357D830012 +:10255000357E830F357F83FF35B8FACD6CAEFB0037 +:102560008335C4FBCD23AD5B2EAD43ADB8FACD2D85 +:10257000AD5BD7FACD4EAD0D2048AD39AD5BD7FA86 +:10258000CD2F03CE3003C610264A2203C6B8FACD9B +:1025900068AEFB008335C4FBCD57AD5B62AD6DAD5E +:1025A0005EAD5BD7FACD75AD64AEFB008335C4FB81 +:1025B000CD6FAD5B7AAD413503C9413603CB05EE36 +:1025C00072067BB8FACDBEDACD5BD7FACD05EE72D6 +:1025D000067BB8FACD60AEFB008335C4FBCDBEDA16 +:1025E000CD5BC6DACD413503C9413603CBEADACD3E +:1025F000BEDACD5BD7FACDEADACD5CAEFB0083352F +:10260000D7FACD46542703CE2803C605EF72066BD2 +:102610004A5A01264D3303CE3403C61020066B34CC +:1026200003C6056B3303C60C264A2203C688888876 +:10263000888888812B03CE2C03C6B8FACD8133035A +:10264000CE3403C6B8FACD814D412503C9412603D6 +:10265000CB81412F03C9413003CB46542703CE28F9 +:1026600003C681D7FACD41BE03C241BF03C031AD1D +:10267000814D41BE03C241BF03C0412303C9412470 +:1026800003CB45AD812F03CE3003C6B8FACD8146CA +:10269000FACD10A6D7FACD81FBB700A94101AB81D5 +:1026A0008B4100A9410EAB5B9883003599830035BF +:1026B0009A8300359B831835B8FACD3CAEFB008376 +:1026C00035C4FBCD25AD5B30AD67ADB8FACD2FADD0 +:1026D0005BD7FACD72AD0D204AAD3BAD5BD7FACDDD +:1026E0002F03CE3003C610264A2203C6B8FACD38CF +:1026F000AEFB008335C4FBCD59AD5B64AD6FAD60FF +:10270000AD5BD7FACD77AD34AEFB008335C4FBCDDE +:1027100071AD5B7CAD413503C9413603CB07EE7229 +:10272000087BB8FACD61D9CD5BD7FACD07EE720838 +:102730007BB8FACD30AEFB008335C4FBCD61D9CD7B +:102740005B69D9CD413503C9413603CBB9D9CD61D8 +:10275000D9CD5BD7FACDB9D9CD2CAEFB008335C42A +:10276000FBCD61D9CD5B69D9CD413103C94132037C +:10277000CB72D9CD61D9CD5BD7FACD72D9CD10AEA0 +:10278000FB008335C4FBCD61D9CD5B69D9CD4A5AF5 +:102790000126AFD9CD0DEE720E7BB8FACD61D9CD41 +:1027A0005BD7FACD4A5A01267CD9CD0CAEFB00830B +:1027B00035C4FBCD61D9CD5B69D9CD0DEE720E7BF1 +:1027C000B8FACD61D9CD5B90D9CD08AEFB00833589 +:1027D000C4FBCD61D9CD5B69D9CD4A5A0126AFD9A9 +:1027E000CD0DEE720E7BB8FACD61D9CD5BD7FACDA7 +:1027F0004A5A01267CD9CD04AEFB008335C4FBCDFB +:1028000061D9CD5B69D9CD0DEE720E7BB8FACD6181 +:10281000D9CD5B90D9CD40AEFB008335F73FF83F73 +:10282000F9B70FA4F9B6D7FACD05EE72067BB8FA60 +:10283000CD28AEFB008335F73FF83FF9B71FA4F969 +:10284000B6D7FACD2703CE2803C67884C7097B798B +:1028500084C70A7B7A84C70B7B7B84C70C7B07EF1A +:1028600072086B4A5A01264D3303CE3403C6066BF9 +:102870002A03C6056B2903C60A6B05AA0A7B20201A +:10288000086B3403C6076B3303C605EF72066B593A +:10289000482903CE2A03C60A6B01AA0A7B1F264ACF +:1028A0002203C6096B80AA097B062604A14603C63B +:1028B000096B20A60A6B0B6B0C6B4F0D6B0EEF7246 +:1028C0003303C9413403CB2D03CE2E03C68B410005 +:1028D000A2410EA05B8184848484BB030135B8FAD5 +:1028E000CDB4AEFB008435F716E7FBCDFBB700A9EE +:1028F0004101AB5B016BE3A4017B016BB484C602B5 +:102900006BB584C6036BB684C6046BB784C630252A +:1029100020A1C803C6B8FACD78AEFB008435C4FB4D +:10292000CDFBB700A94101AB5BF7B703A4F7B6F83D +:10293000B7C0A4F8B6F93FFA3F46FACD16A6F7B7E6 +:10294000F8B7F9B74FFA003D0355016BFCA4017BC2 +:10295000026B3FA4027B016B7884C6026B7984C64C +:10296000036B7A84C6046B7B84C6B8FACD74AEFB65 +:10297000008435D7FACD2003CE2103C6B8FACD7036 +:10298000AEFB008435D7FACD1E03CE1F03C6B8FABE +:10299000CD6CAEFB008435D7FACD1C03CE1D03C62B +:1029A000B8FACD68AEFB008435D7FACD1A03CE1B3A +:1029B00003C6B8FACD64AEFB008435D7FACD180350 +:1029C000CE1903C612206484003565840035668400 +:1029D00002356784CB35122502A21803C6CBA01995 +:1029E00003C61E2602A1C203C6252603A14B03C6A9 +:1029F0002C2420A1C803C6B8FACD60AEFB008435F4 +:102A0000D7FACD1603CE1703C6B8FACD5CAEFB00DD +:102A10008435D7FACD1403CE1503C6B8FACD58AE17 +:102A2000FB008435D7FACD1203CE1303C6888888FD +:102A30008881FBC692FCBFFBB781FBD692FC3FFBB3 +:102A4000B781842003CF1803CE2103C71903C6180A +:102A500003CF1903C74A5A01264D59484003CE41B6 +:102A600003C60B200E264D4003CE4103C60B264A5B +:102A70002203C61E03CF1603CE1F03C71703C617B4 +:102A8000035F7216035F721C03CF1403CE1D03C7CE +:102A90001503C61403CF1503C74A5A01264DFA265B +:102AA0005A90465406273D03CE903E03CE3F03C6C0 +:102AB0001A03CF1203CE1B03C71303C613035F729F +:102AC00012035F723D035F72042604A1C203C60BAA +:102AD0002603A10F202D035F722E03233519260331 +:102AE000A1C203C6202603A115244B03C620A1C8FA +:102AF00003C6400325035541032603554403290318 +:102B00005545032A03553E032303553F032403552C +:102B10004203270355430328035597D3CCC7D5CD8C +:102B2000D0A94109AB521CAE017BB8FACD39AEFB3E +:102B3000000335E9F9CDFBB7D0A94105AB521CAE76 +:102B4000017B3803C7C7D5CDD0A94104AB521CAE19 +:102B5000017B3703C7C7D5CDD0A94103AB521CAE0B +:102B6000017B3603C7FBD692FC3C3503C7BFD5CDEE +:102B7000D0A94101AB521CAE017B33035F72340319 +:102B800001353203C7FBD692FC3C3103C7BFD5CD1C +:102B9000CFA941FDAB521CAE017B3003C7FBD692DF +:102BA000FC3C2F03C7BFD5CDCFA941FBAB521CAE18 +:102BB000017B2E03C7FBD692FC3C2D03C7BFD5CDAE +:102BC000CFA941F9AB521CAE017B2C03C7FBD692B7 +:102BD000FC3C2B03C7BFD5CDCFA941F7AB521CAEF0 +:102BE000017B2A03C7FBD692FC3C2903C7BFD5CD86 +:102BF000CFA941F5AB521CAE017B2803C7FBD6928F +:102C0000FC3C2703C7BFD5CDCFA941F3AB521CAEC7 +:102C1000017B2603C7FBD692FC3C2503C7BFD5CD5D +:102C2000CFA941F1AB521CAE017B2403C7FBD69266 +:102C3000FC3C2303C7BFD5CDCFA941EFAB521CAE9F +:102C4000017B2203C7C7D5CDCFA941EEAB521CAE45 +:102C5000017BE6D4CC0ED5CC032702A1E6D4CC036D +:102C60002603A14B03C63D03C729B639032A0055E5 +:102C70003A032B00553B032C00553C032D005537E0 +:102C800003C713B613B63503CF22BE3603C723B628 +:102C90003303CF20BE3403C721B63103CF1EBE326B +:102CA00003C71FB62F03CF1CBE3003C71DB62D03AD +:102CB000CF26BE2E03C727B62B03CF24BE2C03C7B7 +:102CC00025B62903CF18BE2A03C719B62703CF1488 +:102CD000BE2803C715B62503CF1ABE2603C71BB6E9 +:102CE0002303CF16BE2403C717B62203C728B6AEE8 +:102CF000D3CC03241DA111B60927113D016B4A1144 +:102D0000B68800F0701C050101030003008F004627 +:102D1000001B00AA011E030007000350050100600C +:102D2000A01805010106000300700040001800B063 +:102D3000011B030007000350050100E01BFA04011A +:102D40000006000300800048001C0090013F039033 +:102D500006200300050100C05F3B040001060003DC +:102D600000200030001400A0003703A0052003005D +:102D7000050100E012BD04010007000300800040CF +:102D8000001B0080011E0380060003000501009067 +:102D9000691104000107000300200030001300A0A7 +:102DA000001603A00500030005010040D2DF030068 +:102DB000000600030088001800230040012603409D +:102DC00005000300040100F0FB02020101080006F7 +:102DD00000700010001F00F00005024004E00150E8 +:102DE000030100005A620201010400010080002872 +:102DF000001B00000174022004580220030100108F +:102E0000F76C040101050001002800E0061900E448 +:102E100007EE02E40CD0020005010010F76C04017B +:102E20000105000100280074091900780AEE0278F3 +:102E30000FD00200050100405F8A03010105000177 +:102E4000002800E0061900E407EE02E40CD00200BE +:102E500005010010F76C040101050001002C005869 +:102E60000029001801650498083804800701001043 +:102E7000F76C040101050001002C0010022900D0AC +:102E8000026504500A38048007010010F76C040141 +:102E900001050001002C007E0229003E036504BEEE +:102EA0000A38048007010020EED90801010500015D +:102EB000002C0010022900D0026504500A3804805A +:102EC00007010080F93703000005000100800018A9 +:102ED000002C0020017102C0064002A0050101C0C3 +:102EE000FC9B010000030001007E0018001600207A +:102EF000017102C0062001A005000010F76C04015A +:102F000001050001002C0010021400D002650450DD +:102F10000A1C028007000010F76C04010105000183 +:102F2000002800B8011900BC02EE02BC07D0020064 +:102F3000050100C0FC9B0100000500010040000CE1 +:102F4000002C009000710260034002D002010020BA +:102F5000EED9080101050001002C005800290018D5 +:102F6000016504980838048007010080F9370300E0 +:102F700000060007007C002000240014010D02B4AC +:102F800006E001A0050101C0FC9B01000003000454 +:102F9000007C002600120014010D02B406F000A00F +:102FA00005000010F76C040101050001002C005819 +:102FB0000014001801650498081C02800700001026 +:102FC000F76C0401010500010028006E0019007271 +:102FD00001EE027206D00200050100C0FC9B010058 +:102FE00000060007003E00100024008A000D025A6F +:102FF00003E001D002010080858001000002000191 +:1030000000600010002300A0000D022003E00180FA +:10301000020181848B4100A94108AB5B096B016B04 +:103020004F012001A604269803C1057B0B2604E16D +:10303000729903C608279803C6B72655FBCDFBB780 +:1030400000A94102AB5BE7FBCDFBB700A94106AB92 +:103050005B066B3048C6076B3148C6086B3248C602 +:10306000096B3348C684842F1ECD74AE08A6024B6C +:10307000004B026B067B036B077B046B087B056BC5 +:10308000097B066B3048C6076B3148C6086B32486F +:10309000C6096B3348C6016B4F8B4100A24109A0A2 +:1030A0005B8118E7FEC692FFBF9019CECC17B6170A +:1030B000B780AA027BC62505A10D6B4C0D7BD225DE +:1030C00004A10C6B4C0C7B18CECC0327A0E118E6B6 +:1030D0009097900CEB720BEB7248480D7B9701EBCD +:1030E0007248480D7B016B0CE07203A60C6B4F0D10 +:1030F0006B4F84842F1ECD74AE20A6144B8807AB73 +:103100000B7B761DCD84B417CD00AE18A6880AAB14 +:103110000B7BFD16CDAE2504A10D6B4C0D7B74AD64 +:10312000FE3C02249790FFBB0DE07203A693FFBF05 +:10313000FEB700A94107AB5B93909706AB0DEB720E +:103140000B7B56CFCDFE3C02249790FFBB0DE07267 +:1031500003A693FFBFFEB700A94103AB5B93905C4E +:103160005C970DEB720B7B0D6B4F076B2C48C60801 +:103170006B2D48C6096B2E48C60A6B2F48C6036BD9 +:103180002848C6046B2948C6056B2A48C6066B2B1F +:1031900048C6F02505A10D6B4C9F18E79803D60D86 +:1031A000EE720D6B12264A027B84842F1ECD74AE04 +:1031B00043A6880C7B074B19E79903C618E79803C9 +:1031C000C60BEE724DCFCC0326027B0B6B5205AEC5 +:1031D000E82414A1026B7FA49803C681848B41006C +:1031E000A9410CAB5B0D6B4F0D99030772052002D3 +:1031F00098030F7284842F1ECD74AE41A6024B003B +:103200004B192660A160A49803C684842F1ECD7438 +:10321000AE40A6014B004B8B4100A2410DA05B814B +:103220007B03C67B0301350498030D7284842F1E33 +:10323000CD74AE40A6014B004B7B035F7281859A33 +:10324000B8FACD14AEFB004835F7B7F8B7F9B74F69 +:10325000FA007E035510487F03551148800355122C +:103260004881035513488203559BCD2505A1016B69 +:103270004C017BBEFBCD7FAEFB00033546FACD484B +:1032800048489FF7B7F8B7F9B74FFAB79803D60190 +:10329000EE721F207E039C0355072604A1016B4F8D +:1032A00084847F035F7280035F7281035F72820395 +:1032B0005F722F1ECD74AE4F054B004B8881848BFF +:1032C0004100A94108AB5B096B016B850A1FCD74F6 +:1032D000AE10A6054B9C03C7057B026B9003C6038B +:1032E0006B9103C6046B9203C6056B9303C69B03E5 +:1032F000C7027B9A03C7037B9903C7047B9803C764 +:10330000057B026B8C03C6036B8D03C6046B8E03B7 +:10331000C6056B8F03C6016B850A1FCD74AE18A658 +:10332000084B9F03C7067B9E03C7077B9D03C70807 +:103330007B9C03C7097B066B1C48C6076B1D48C6F0 +:10334000086B1E48C6096B1F48C69B03C7067B9ABD +:1033500003C7077B9903C7087B9803C7097B066BE4 +:103360001848C6076B1948C6086B1A48C6096B1B74 +:1033700048C6016B4F8B4100A24109A05B81858546 +:10338000858585017B016B01A6042614A1027B0AB9 +:103390002614A1037BD12505A1056B4C057BDD25FA +:1033A00008A1046B4C047B98034472026B4C027BB3 +:1033B0000520036B4C037B072601A49803D605EE7A +:1033C00072046B4F056B4F44204F032785854D2FAB +:1033D0001ECD74AE054B004B9A144890035515480A +:1033E0009103551648920355174893035510488C7E +:1033F000035511488D035512488E035513488F030A +:10340000559B036B026B016B4F888888888881FB12 +:10341000004835F7B7F8B7F9B74FFAB78185858512 +:1034200085017B9AB8FACD0CAE0DAD037B9B016B89 +:1034300001A60426027B04264A037BEE26027B06B5 +:1034400026037B026B4A027B036B0F48C60A209A55 +:10345000B8FACD5F38AD047B9B026B32A6016B03DB +:103460006B4F8888888881E7FBCDFBB700A94105B1 +:10347000AB8184848484848484849AB8FACD04AE35 +:10348000FB004835FA15F7B7F8B7F9B74FFAB703A5 +:10349000AA3FA4087B9B056B0448C6066B0548C67B +:1034A000076B0648C6086B0748C69AB8FACD5FFB9B +:1034B000004035C4FBCDFBB700A94101AB5BFA145A +:1034C0004FAD5BB8FACDFBB700A94101AB5BF7B7D5 +:1034D000F8B7F9B74FFA007803559B056B0040C663 +:1034E000066B0140C6076B0240C6086B0340C69AD4 +:1034F000B8FACDB4AEFB008435FA1AFA198FCBCDE9 +:103500005B9B056BB484C6066BB584C6076BB6843B +:10351000C6086BB784C6888888888888888881E7C9 +:10352000FBCDFBB700A94101AB81848484849AB8A8 +:10353000FACD04AEFB004835FA1411AD5B9B016B6C +:103540000448C6026B0548C6036B0648C6046B07F1 +:1035500048C69AB8FACD5FFB004035FA1534AD5B2A +:103560009B016B0040C6026B0140C6036B0240C664 +:10357000046B0340C68888888881858585854F9A35 +:10358000B8FACD04AEFB004835F73FF83FF93FFAF3 +:10359000B730A4FAB6F7B7F8B7F9B74FFAB7047B64 +:1035A0009B016B0448C6026B0548C6036B0648C600 +:1035B000046B0748C69AB8FACD5FFB004035FA1590 +:1035C000E7FBCDFBB700A94101AB5B9B016B004062 +:1035D000C6026B0140C6036B0240C6046B0340C6C3 +:1035E00088888888819A9BFACDFBB740A94100ABB7 +:1035F00081FBB700A94107AB818B4100A9410DAB0D +:103600005B9AB8FACD30AEFB004235C4FBCDFBB7B8 +:1036100000A94101AB5B46FACD4848127BF73FF861 +:103620003FF93FFA0003359B016B3042C6026B3114 +:1036300042C6036B3242C6046B3342C639C9CC035F +:103640002506E172FBD69202AEFCB70D7BFBB70CF0 +:103650007B066B04AB067B67AD5C012406EB721046 +:10366000EE72117BE7FBCD6FAD5B9BAF2504A10B29 +:103670006B4C0B7BFBC792FCBF85FB0032FBD692E9 +:1036800003AEFCBFFBB70EE972410FEB725F4A0756 +:103690006B4C077BFB003B89FB3C022497FCBB0B7C +:1036A000E07203A6FCBF08CACD5B362505E172FBBC +:1036B000D69202AEFCB70D7BFBB70C7B0B6B076B96 +:1036C000086B096B0A6B4F7420056B4F106B00A9D8 +:1036D000107B116B04AB117B10CACD10EE72117B05 +:1036E000E7FBCD08CACD5B9B076B4F086BFBD692FF +:1036F0005C096BFBD69201AEFCB70D7BFBB70C7B74 +:103700000A6BFBC692FCB70D7BFBBF0CEE728B41C4 +:1037100000A2410BA05B89888101A61500DE35144B +:1037200000C0351300AD351200DE35A7F6CD81841B +:103730008484848493C7CDAC2510A1046B4C047B96 +:10374000C22508A1056B4C057BDBC7CD03275D03B4 +:10375000264D4101E4724102E472FA265A9059481A +:10376000062705E67201A601EF72026B5F037B007C +:10377000C8CD03209AAD0426057B0826047B056B83 +:103780004F036B12E69704E0720FA6046B4FF5250A +:1037900010A1046B4C047B97AD046B4FDBC7CD933A +:1037A000C7CDBDC7CD888888888881B3840035B0EF +:1037B000840035B184003581B0840035B184003592 +:1037C000B28400350DADB284033513ADB284023539 +:1037D00019ADB2840035B384003581B0840035B1B1 +:1037E000840035B2840035B38400358101ADB084E6 +:1037F0000035B1840035B2840135B384003513AD92 +:103800008164A6B0840035B184003526C0CC03ADF8 +:10381000B2840035B384003526C0CD10ADB2840427 +:1038200035B384003581AD840035AE840035AF8476 +:10383000003581AC84003505AD81AC8480350CAD9C +:1038400007274D26C0CC64A6B0840035B18400356E +:10385000B2840035B384003526C0CD0AA6B08400FA +:1038600035B1840035B2841035B384003581848449 +:103870008484BB030135B8FACD5FFB008435F71AA9 +:10388000E7FBCDFBB700A94101AB5B016B0084C630 +:10389000026B0184C6036B0284C6046B0384C68872 +:1038A0008888888184848484B8FACD5FFB0084355D +:1038B000F71BE7FBCDFBB700A94101AB5B016B0038 +:1038C00084C6026B0184C6036B0284C6046B038446 +:1038D000C68888888881B8FACD78AEFB00843581A7 +:1038E000E7FBCDFBB700A94101AB81848484841040 +:1038F000ADFA1D09AD5B17ADFA1C10AD5B016B781D +:1039000084C6026B7984C6036B7A84C6046B7B849D +:10391000C68888888881D7FACD9802CE9902C68158 +:1039200084848484A084C7017BA184C7027BA28491 +:10393000C7037BA384C7047B036B80AA037B046B50 +:1039400006AA047B0C20BEFBCDFBB700A94101AB4E +:103950005BF91E34AD112400A29802C606A099029C +:10396000C60C274C03C6222502A19702C629264A67 +:103970004B03C6036B80A4037B046B4F016BA084D5 +:10398000C6026BA184C6036BA284C6046BA384C663 +:103990006C2502A19702C673264A4B03C60D274A1F +:1039A0004C03C6B8FACD78AEFB008435F71CE7FBB4 +:1039B000CDFBB700A94101AB5B016B7884C6026BFC +:1039C0007984C6036B7A84C6046B7B84C648830003 +:1039D00035498300354A8300354B830F3510264A1D +:1039E0002483003525830035268300352783003561 +:1039F0004D274B03C6B8FACDA4AEFB008435F91EA3 +:103A0000F73FF83FF91FE1C6CD142603A1042701B3 +:103A1000A19702C61F264A4B03C6B8FACDA0AEFB3B +:103A2000008435F71FF93FFA3F46FACD10A6D7FAC2 +:103A3000CD5C012402AB3303CE3403C60B20C0039C +:103A4000CEC103C62A264A0B2702A04B03C6C703D2 +:103A50005F725DC6CC03274D03C608274C03C6889A +:103A60008888888184848484A084C7017BA184C7DA +:103A7000027BA284C7037BA384C7047BBEFBCDFB70 +:103A8000B700A94101AB5BF91ED7FACD9802CE99D8 +:103A900002C6036B80A4037B046B4F1F2502A19712 +:103AA00002C626264A4B03C6036B7FA4037B016B29 +:103AB000A084C6026BA184C6036BA284C6046BA358 +:103AC00084C65A264C03C65F202483003525830014 +:103AD000352683023527830035A0840035A1840074 +:103AE00035A2840035A3840035A4840035A5840064 +:103AF00035A6840035A7840035B8FACD78AEFB0032 +:103B00008435F71DE7FBCDFBB700A94101AB5B0195 +:103B10006B7884C6026B7984C6036B7A84C6046BA7 +:103B20007B84C6C703C75F264C03CE64264D03C6FD +:103B30008888888881E7FBCDFBB700A94101AB816C +:103B4000848484840040C7017B0140C7027B02401B +:103B5000C7037B0340C7047BB8FACD5FFB00403549 +:103B6000F71E23AD5BB8FACD1CAEFB004035F7B7AE +:103B7000F8B7F9B74FFAB713B614201C4000351D3B +:103B80004000351E4000351F400035046B02AA047A +:103B90007B1826123D046B40AA047B06263803C618 +:103BA000046B10AA047B06263703C6016B026B0365 +:103BB0006B4F046B01A6B8FACDB4AEFB008435FAA6 +:103BC00018F918C1C4CD5B016BB484C6026BB5840F +:103BD000C6036BB684C6046BB784C626C0CDFAA6EE +:103BE0001445003515450035164500351745023595 +:103BF00088888888810140003502400035034000F4 +:103C00003581848484844D035F72B8FACDB4AEFBF1 +:103C1000008435F919E7FBCDFBB700A94101AB5B87 +:103C2000016BB484C6026BB584C6036BB684C6044C +:103C30006BB784C61445003515450035164500356B +:103C4000174501350040003547AD004080354DAD8A +:103C50008888888881B8FACDB4AEFB008435F91E17 +:103C600081AC840035AD840035AE84003581FBB76E +:103C700000A94105AB81FBB700A94101AB81FBB7AE +:103C800000A94109AB810088003501880035028810 +:103C9000003581F914FA14F73FF83FF9B701A4F998 +:103CA000B6FAB7F8A4FAB6D1F9CD08AE905FC6035C +:103CB000C6818B4100A9410EAB5B28AD038801355D +:103CC00008880035098830350A8800350B880035AA +:103CD000B8FACD0CAEFB008835FA1EF7B7F8B7F985 +:103CE000B74FFAB707A40D7B18880035198800353F +:103CF0001A88FF351B88FF35148800351588003574 +:103D00001688FF351788FF351088003511885F3514 +:103D10001288FF351388FF356EC3CD03880035A0A8 +:103D2000C3CDF71EE7FBCD83C3CD5B0C2621A110CD +:103D3000209084C7057B9184C7067B9284C7077B4C +:103D40009384C7087BB8FACD8BC3CD5BC4FBCD830E +:103D5000C3CD5BC4FBCD7BC3CD5BF71EE7FBCD8B37 +:103D6000C3CD5B056BBFA4057B066BC3A4067B07B5 +:103D70006B086B4F9FFBCD10A68BC3CD5B9FFBCD1C +:103D800010A67BC3CD5B096B0A6B0B6B4F0C6B3CB6 +:103D9000A60B2082FBCD04A67BC3CD5B0B2455FB79 +:103DA000CD61AEFB00C135E7FBCD7BC3CD5B096BBD +:103DB0000A6B0B6B4F0C6B3CA4087B3E20096B4FCE +:103DC0000A6B04A60B6B0C6B4F0E2430A1C803C604 +:103DD000056B9484C6066B9584C6076B9684C608EB +:103DE0006B9784C6016B026B4F016B9884C6026BA4 +:103DF0009984C6036B9A84C6046B9B84C6A0C3CD0A +:103E0000F7B760AAF7B6E7FBCD83C3CD5BD1C2CCD1 +:103E1000032422A1C803C6016BB484C6026BB58417 +:103E2000C6036BB684C6046BB784C693C3CDAF8498 +:103E30002035B8FACD7CAEFB008435F714F81AF8BB +:103E4000104FC3CD0920F81AF8104FC3CD1220F837 +:103E5000104FC3CD19204FC3CD272017274A112754 +:103E60004A0D274A0B274A0D7B93C3CDAF840035FB +:103E70007C8400357D8400357E8400357F84003568 +:103E80006EC3CD03880035D8C0CD212520A1C8033D +:103E9000C68B4100A2410CA05B89883C00000081D8 +:103EA000AC840035AD840035AE840035AF84003578 +:103EB0007C8400357D8400357E8400357F84003528 +:103EC00000880035018800350288003503880035F8 +:103ED000A8AD022520A1C803C64B035F72B9035FDA +:103EE000728184848484B484C7017BB584C7027BD7 +:103EF000B684C7037BB784C7047BB8FACDB4AEFBE6 +:103F0000008435F81CE7FBCDFBB700A94101AB5B92 +:103F1000016BB484C6026BB584C6036BB684C60459 +:103F20006BB784C68888888881E7FBCDFBB700A97A +:103F30004103ABB8FACC5FFB008435F70030350C99 +:103F4000AD5BB8FACD5FFB008435F71AF73F1BADC8 +:103F50005B81F73FE7FBCDFBB700A94103ABB8FAA4 +:103F6000CC5FFB008435F7180AAD5BB8FACD5FFB78 +:103F700000843515AD5B818590859001EE72027BE2 +:103F8000052005EE72067B072405E2729F06E072AB +:103F90008988818590859005EE72067B052001EE6B +:103FA00072027B072405E2729F06E0728988818491 +:103FB00084E926FBB6ED265D016B00A2FBB7017B11 +:103FC000026B01A097027B9D012001EF72026B063C +:103FD000FACD03AE90FE3F5F88888141204035488E +:103FE000205F7246205F724520C701A60220D8A636 +:103FF000042420A1C803C6819AB203CFB303C79B90 +:1040000000000000000000000000000000000000B0 +:1040100000000000000000000000000000000000A0 +:104020000000000000000000000000000000000090 +:104030000000000000000000000000000000000080 +:1040400000000000814F13B75320C6502012728128 +:1040500001A603274DB61DCD88A612B75320C65022 +:104060002015728101A603274DB61DCD88A68101BA +:10407000A603274D131ECD41A68101A603274DFEA1 +:104080001DCD86025F725020203552200935814DAA +:10409000B61DCD88A6502020355320C7C5204F50CF +:1040A000201272EC2506E172016B4C017BD42613C1 +:1040B000AD9803D601EE720D204F172760A1027B49 +:1040C00026C0CD05A6EC262BAD037BF2264DB61DF2 +:1040D000CD88A68185858501A606274D131ECD02B4 +:1040E0007B08264DFE1DCD86025F72502020355282 +:1040F000200935888988814DB61DCD88A64F1ECCF4 +:104100004F26C0CD05A6952506E172017B9803D701 +:104110005320C6016B4C9F01EE720D2011E7532016 +:10412000C69707EB724A016B4C017B112509A1066A +:104130007B502022350426FFB1FFBF900B26FEB333 +:10414000FE3F01E6724A5A01264D5F067B5020155C +:10415000720426FFB1FFBF900B26FEB3FE3F01E6BF +:10416000725A012402A05F1A2502A1067BBA2672A8 +:10417000AD5020157204264A067BC7264D90AD012E +:10418000AA027BD0264D84AD26C0CD05A6DA260333 +:104190001FCD502020355320C7037B02205280AE14 +:1041A000037B072680A1067BF526031FCD8185852D +:1041B0008501A606274DC9AD027B07264DBBAD86FE +:1041C000025F72016B4F50202035522009358889DB +:1041D00088814F5020243526C0CD05A68101A60335 +:1041E000274DB7AD82A6502021355320C7814F26D9 +:1041F000C0CD05A68101A603274DCFAD81A65020D5 +:10420000293581854F86025F72818501A686025F0E +:1042100072502022350C86020D72052601E17201D2 +:10422000E472FA278602C68F01208881854F818536 +:1042300001A650200535082701E17201E4725120E2 +:10424000C6FA51200F729D0120880218CCF5B545A1 +:10425000F4B445F33FF23FF13FF03FEF3FEE3FF65E +:104260002538A3F6BEB66FF63C04200218CDF4251F +:1042700040A1F6B6B66FF63CF6BE0820172539A168 +:10428000F6B6B6E780A6F63CF6BE8106FCCDFBB7D7 +:1042900000A941C6AB5204AE8106FCCDFBB700A914 +:1042A00041CEAB5204AE8106FCCDFBB700A941FA6A +:1042B000AB5204AE81E9F9CDFBB700A941E6AB52A0 +:1042C00004AE81FBB700A94101AB81F7B7F8B7F99C +:1042D000B74FFAB7B6E681B8FACDFBB700A9410DE2 +:1042E000AB810FFBCDFBB700A94111AB81FBB70040 +:1042F000A94119AB81FBB700A94105AB81FBB70010 +:10430000A94115AB81E7FBCDFBB700A9411DAB81EE +:10431000FBB701A94106AB5204AE81FBB700A9412E +:1043200009AB81E7FBCDFBB700A94121AB818B41F4 +:1043300000A94125AB5BF63F2FFACDB0AEE7FBCD30 +:10434000FBB700A94111AB5B2FFACDACAEE7FBCDBB +:104350005CAD5B2FFACDA8AEE7FBCD57AD5B2FFA76 +:10436000CDA4AE36AD5B2FFACDA0AE5CAD5BC61B67 +:10437000CC032450A1256B4C257B1D6B0D7B1E6B44 +:104380000E7B1F6B0F7B206B107B216B1D7B226BC9 +:104390001E7B236B1F7B246B207BB8FACDFC1CCDCE +:1043A0005BC4FBCDDE1CCD5B46FACD1EA6D31CCD77 +:1043B0005BB8FACDDE1CCD5B7AFACD02A6D31CCD5C +:1043C0005B196B157B1A6B167B1B6B177B1C6B18B1 +:1043D0007B116B197B126B1A7B136B1B7B146B1C91 +:1043E0007B1F1DCD5B0FFBCDFEAEFB0017350FFB1A +:1043F000CDE61CCD257B141DCD5B0FFBCDDE1CCD8A +:104400005BC4FBCD041DCD5B46FACD05A6F11CCDEA +:104410005BB8FACD041DCD5B7AFACD1BA6F11CCD9D +:104420005BB8FACDDE1CCD5B06FCCD0C1DCD5B066A +:10443000FCCDFC1CCD5BD31CCD5B256B3CA6D31AFD +:10444000CC03243CA1256B4C257B1D6B0D7B1E6B87 +:104450000E7B1F6B0F7B206B107B216B1D7B226BF8 +:104460001E7B236B1F7B246B207BB8FACDFC1CCDFD +:104470005BC4FBCDDE1CCD5B46FACD1EA6D31CCDA6 +:104480005BB8FACDDE1CCD5B7AFACD02A6D31CCD8B +:104490005B196B157B1A6B167B1B6B177B1C6B18E0 +:1044A0007B116B197B126B1A7B136B1B7B146B1CC0 +:1044B0007B1F1DCD5B0FFBCDFAAEFB0017350FFB4D +:1044C000CDE61CCD257B141DCD5B0FFBCD041DCD92 +:1044D0005BC4FBCD361DCD5B46FACD05A6F11CCDE8 +:1044E0005BB8FACD361DCD5B7AFACD1BA6F11CCD9B +:1044F0005BB8FACD041DCD5BC4FBCDDE1CCD5B32B9 +:10450000FBCDFBB700A94121AB5BC4FBCD0C1DCD9E +:104510005BE7FBCDFC1CCD5BB8FACDDE1CCD5B327E +:10452000FBCD0C1DCD5BE7FBCDFC1CCD5B256B28CB +:10453000A6031ACC032428A1256B4C257B1D6B0DEB +:104540007B1E6B0E7B1F6B0F7B206B107B216B1D0B +:104550007B226B1E7B236B1F7B246B207BB8FACDE9 +:10456000FC1CCD5BC4FBCDDE1CCD5B46FACD1EA68C +:10457000D31CCD5BB8FACDDE1CCD5B7AFACD02A69A +:10458000D31CCD5B196B157B1A6B167B1B6B177BD2 +:104590001C6B187B116B197B126B1A7B136B1B7BCB +:1045A000146B1C7B1F1DCD5B0FFBCDF6AEFB001704 +:1045B000350FFBCDE61CCD257B141DCD5B0FFBCD50 +:1045C000DE1CCD5BC4FBCD041DCD5B46FACD05A63C +:1045D000F11CCD5BB8FACD041DCD5B7AFACD1BA6DC +:1045E000F11CCD5BB8FACDDE1CCD5B06FCCD0C1DFD +:1045F000CD5B06FCCDFC1CCD5BD31CCD5B256B14C9 +:10460000A61919CC032414A1256B4C257B1D6B0D19 +:104610007B1E6B0E7B1F6B0F7B206B107B216B1D3A +:104620007B226B1E7B236B1F7B246B207BB8FACD18 +:10463000FC1CCD5BC4FBCDDE1CCD5B46FACD1EA6BB +:10464000D31CCD5BB8FACDDE1CCD5B7AFACD02A6C9 +:10465000D31CCD5B196B157B1A6B167B1B6B177B01 +:104660001C6B187B116B197B126B1A7B136B1B7BFA +:10467000146B1C7B1F1DCD5B0FFBCDF2AEFB001737 +:10468000350FFBCDE61CCD257B141DCD5B0FFBCD7F +:10469000041DCD5BC4FBCD361DCD5B46FACD05A612 +:1046A000F11CCD5BB8FACD361DCD5B7AFACD1BA6D9 +:1046B000F11CCD5BB8FACD041DCD5BC4FBCDDE1C77 +:1046C000CD5B32FBCDFC1CCD5BD31CCD5BB8FACDF2 +:1046D000DE1CCD5B32FBCD0C1DCD5BF733F833F91F +:1046E00033FA33D31CCD5B256B4F116BB0B6126B15 +:1046F000B1B6136BB2B6146BB3B6196BACB61A6B1A +:10470000ADB61B6BAEB61C6BAFB6156BA8B6166B11 +:10471000A9B6176BAAB6186BABB6216BA4B6226B01 +:10472000A5B6236BA6B6246BA7B61D6BA0B61E6BF1 +:10473000A1B61F6BA2B6206BA3B6AE2550A1256B08 +:104740004C257B9BFACDE61CCD257BC4FBCDDE1C26 +:10475000CD5BF739F839F939FA38681DCD257B5A20 +:104760001DCD257B4C1DCD257B3E1DCD257BB8FA6F +:10477000CDDE1CCD5B7AFACD1FA6681DCD257B5AF8 +:104780001DCD257B4C1DCD257B3E1DCD256B10A65B +:104790009D2510A1256B4C257BBEFBCDE61CCD25B0 +:1047A0007B2A1DCD9703AB9F585825EE72BEFBCDDB +:1047B000E61CCD257BE0FACD5F90FE0001355FB6AB +:1047C000E65C5C585825EE72BEFBCDE61CCD257B21 +:1047D00046FACD10A62A1DCD5C585825EE729BFADC +:1047E000CDE61CCD257B46FACD18A62A1DCD5858FE +:1047F00025EE72256B4F8B4100A24125A05BD6C1EF +:1048000062CADCBC1B8FA1EBD96E9979825A818474 +:1048100084C9264C056B4A057B016B00A9017B020C +:104820006B01AB027B27AD022640A1F6B6B43C0279 +:1048300024B5B708ABB5B6B6E7F63CF6BEFBC692F4 +:10484000FCB7027BFBB7017B2F208988818484849D +:10485000B4B7B4B99FB5B7B5BB5208AEF6B7037BD2 +:10486000EF2503E172016B4C9FB6E74602D601EEDD +:10487000720A204F76ADB4000235B53FF6004035E0 +:10488000F12540A1016B4C9FB6E701EE72027B015E +:104890006B19A6ED2519A1016B4C9FB6E702E872D2 +:1048A00060FED601EE72016B4F88898881B000C32B +:1048B00035B100D235B200E135B300F035AC0010AF +:1048C00035AD003235AE005435AF007635A80098CE +:1048D00035A900BA35AA00DC35AB00FE35A400EFDF +:1048E00035A500CD35A600AB35A7008935A00067FA +:1048F00035A1004535A2002335A3000135F63FB5AB +:104900003FB43F818484761DCD5DAD5CAE14A60CB2 +:10491000ADDE2505A1026B4C027BEA2504A1016BEB +:104920004C017B4602D7A0E69701EB724848027B18 +:10493000016B4F026B4F761DCD5417CD36AE05017E +:10494000C63EAD05013235F02532A1026B4C9F46C3 +:1049500002D7CDA602EE72026B4F88883A15CC289A +:104960004B1CCACD3E15CCC1A6004B084B87CACD07 +:104970003E15CCE0A6014BE04BBF15CC03267503DA +:104980005A7281848475030235DF14CDE0A6014B91 +:10499000E04B10274D5FCFCD28277703C57903C69D +:1049A0003E15CCC1A6004B284B3C15CC014B904B7F +:1049B0001CCACD0A277703C57903C6C520284B3EFC +:1049C00015CCE0A6014B904BE2CACD0C277703C56E +:1049D0007903C6DD20084B3E15CC82A6014B904BD7 +:1049E00076035A72CE277603C612264DE1CDCD3E10 +:1049F00015CCC0A6004B504BB7274D5FCFCDE82656 +:104A00004D9ACBCD03A6262076030A35CB274D5FE2 +:104A1000CFCDD320604B04274D9ACBCD83A618274A +:104A20004DC3CDCD3E15CC81A6004B604BEC264D41 +:104A30009ACBCD02A643CDCD3E15CCA0A6004B0807 +:104A40004B09274D83CCCD06264D9ACBCD4C8C20DF +:104A500080A688884F932040A6004BA04B08264D87 +:104A6000F2CBCD9C16CC6016CC03261FA04516CCED +:104A700003264A2D16CC032620A0E0271EA01116DF +:104A8000CC03264A60274A392720A0C32720A02C20 +:104A90002720A0302720A09C16CC03268303C6DD48 +:104AA0002060A6004B504B1CCACD032561A1830397 +:104AB000C6122711A17C03C607277A03C681848406 +:104AC0009FAD20A6004B504B0B264D03C6052783F8 +:104AD00003C610204F004BA04B1CCACD03278303F5 +:104AE000C60F267D03C68184848400C0CD06EE7285 +:104AF000077B8303C7037B05201872042701E1723B +:104B0000F0A48303C6016BF0A4037B0620C7026BED +:104B100002EA72E0A4037B026B1FA40620C6888809 +:104B200088814442003545420035464200354742BF +:104B30000035004200350142003502420135034292 +:104B4000013510200042083501420035024201358E +:104B50000342003512264A9B02C620400035214000 +:104B60000035224000352340013504449E0255059E +:104B7000449F02550644A002550744A10255004433 +:104B8000A202550144A302550244A402550344A5C0 +:104B9000025581854FF3259B02C1016B4C017B7649 +:104BA00012CD06204F88819A9BFACDF73FF83FF946 +:104BB0003F81F7B7F8B7F9B74FFAB7819A9BFACDAB +:104BC000FBB701AA4181FBC692FCBFFBB7811DADBB +:104BD000FA3FFBB701AA3313CC4F29ADFA003D359C +:104BE00003EE72FBB7027B9B37ADFA000835FBB7CB +:104BF00002AA4124AA02EE72037B9BD32604E1722F +:104C000033AD02AA4103AA02EE72037B3213CC0336 +:104C100026016B4A017B9A9BFACDFBB702AA027B65 +:104C200003EE7268AD047B9B1C20016BFFA6046B36 +:104C300080AA047B062602A111B6046B03A60220FB +:104C400001A6062002A60427153D0C279C02C67962 +:104C5000AD411CAA02EE72037B9B2A14CD4118AA17 +:104C600002EE72037B9B2A14CD4114AA02EE72035A +:104C70007B9BD72604E1723314CD01AA4113AA020B +:104C8000EE72037BB627016B4A017B3B14CD10AA61 +:104C900002EE72037B4514CD047B9B1720016BFF52 +:104CA000A6046BCFA602200FA606200CA60820069D +:104CB000274A052714B6CC2604E1723314CD01AA85 +:104CC000410DAA02EE72037B81858585854C0626FF +:104CD000016B4A017B3B14CD0CAA02EE72037B46AA +:104CE000FACD10A64514CD047B9B2220016BFFA6B4 +:104CF000046BFCA60220F0A60620CCA60A20C0A6C3 +:104D00000E200CA612200FA616200CA618274A1754 +:104D1000274A16274A15274A14274A29274A1627B9 +:104D200013B6C92604E1723314CD01AA410BAA02BD +:104D3000EE72037B6627016B4A017B3B14CD08AA08 +:104D400002EE72037BF7B703AAF7B6F8B7C3AAF768 +:104D5000B7F9B74FFAB7047B9B2520016BFFA60478 +:104D60006B4F01200CA60427153D2A14CD4104AA3F +:104D700002EE72037B9B2A14CD9B026B03EF7250F1 +:104D8000AA414F5858978888888881E7FBCDA2AE02 +:104D9000FB00023581FBB700A94101AB81F7B7F8F1 +:104DA000B7F9B74FFAB781F7B703A4F7B6F83FF9E9 +:104DB0003FFA3F46FACD18A61DFACD4A81FBB7004F +:104DC000A94107AB81A2020035A3020035A4021855 +:104DD00035812CAD18A44848484A12B6B8FACD43DC +:104DE000AD818B4100A9410AAB5BB8FACD0CAEFB9B +:104DF000008435FA36F936F836F73467AD0A20F70D +:104E000039F839F939FA3873AD0C2602A111B68494 +:104E1000848484841FDDCD880B7B880B7B880B7B8F +:104E2000880B7B88067B066B4444067B9FFBCD0288 +:104E3000A66DAD5B0E2602A111B6066B08A6076B28 +:104E40004F086BBBA6096B80A60A6BA2020035A3B4 +:104E5000020035A4026035A50200351820ACA60971 +:104E60006B44A60A6BA2020035A3020035A40262BD +:104E700035A5020035392010A6076B4F086B5DA6DB +:104E8000096BC0A60A6BA2020035A3020035A4027A +:104E90003035A5020035182056A6096B22A60A6BEC +:104EA000A2020035A3020035A4023135A502003567 +:104EB000742020A6076B4F086B2EA6096BE0A60A8C +:104EC0006B2F12CDA5020035C411CC20A6076B4F65 +:104ED000086B2BA6096B11A60A6B2F12CDA50280B9 +:104EE00035C411CC20A6076B4F086B1FA6096B4079 +:104EF000A60A6BA2020035A3020035A4021035A554 +:104F0000020035C411CC20A6076B4F086B2EA609F2 +:104F10006BE0A60A6B4F2F12CDA5020035A511CC70 +:104F200003264A8B11CC03264A6A11CC03264A5029 +:104F300011CC03264A6D274A57274A382713B69AB9 +:104F4000B8FACDFBBF84AEFA1AE7FBCD3C12CD5BBD +:104F50009BBEFBCD3C12CD5BC4FBCD6412CD5B1F71 +:104F600012CD5B4412CD5A01264D5F12B61520FAC0 +:104F700010C4FBCD6412CD5B1F12CD5B4412CD5A21 +:104F800001264D5F12B619264A11B63A20086B4029 +:104F9000AA087B0A6B02AA0A7B0E2602A111B60A96 +:104FA0006B04AA0A7B0627163DB8FACD3C12CD5BEE +:104FB000F91EF7BFF8B73EA4F8B6F9BFFABF46FA34 +:104FC000CD11A65A12CD1420F714F73FF8B73EA41E +:104FD000F8B6F93FFA3F46FACD11A65A12CD182776 +:104FE000B803CE056B18A6022014A6062010A6084A +:104FF0002006274A052714B68B4100A2410AA05B70 +:00000001FF diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 3c9b616c834..b3d7e23440e 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -151,6 +151,7 @@ header-y += hid.h header-y += hiddev.h header-y += hidraw.h header-y += hpet.h +header-y += hwmem.h header-y += hysdn_if.h header-y += i2c-dev.h header-y += i2c.h diff --git a/include/linux/clonedev.h b/include/linux/clonedev.h new file mode 100644 index 00000000000..575233f07e9 --- /dev/null +++ b/include/linux/clonedev.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * ST-Ericsson Display overlay compositer device driver + * + * Author: Per-Daniel Olsson <per-daniel.olsson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef _CLONEDEV_H_ +#define _CLONEDEV_H_ + +#if !defined(__KERNEL__) && !defined(_KERNEL) +#include <stdint.h> +#else +#include <linux/types.h> +#include <video/mcde.h> +#endif + +#if defined(__KERNEL__) || defined(_KERNEL) +#include <linux/mm_types.h> +#include <linux/bitops.h> +#else +#define BIT(nr) (1UL << (nr)) +#endif + +#define CLONEDEV_DEFAULT_DEVICE_PREFIX "clone" + +/* Cloning mode */ +enum clonedev_mode { + CLONEDEV_CLONE_NONE, + CLONEDEV_CLONE_VIDEO_OR_UI, + CLONEDEV_CLONE_VIDEO_AND_UI, + CLONEDEV_CLONE_VIDEO, + CLONEDEV_CLONE_UI, +}; + +#define CLONEDEV_SET_MODE_IOC _IOW('D', 1, __u32*) + +#ifdef __KERNEL__ + +int clonedev_create(void); +void clonedev_destroy(void); + +#endif /* __KERNEL__ */ + +#endif /* _CLONEDEV_H_ */ + diff --git a/include/linux/compdev.h b/include/linux/compdev.h new file mode 100644 index 00000000000..83285c61b62 --- /dev/null +++ b/include/linux/compdev.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * ST-Ericsson 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. + */ + +#ifndef _COMPDEV_H_ +#define _COMPDEV_H_ + +#if !defined(__KERNEL__) && !defined(_KERNEL) +#include <stdint.h> +#else +#include <linux/types.h> +#include <video/mcde.h> +#endif + +#if defined(__KERNEL__) || defined(_KERNEL) +#include <linux/mm_types.h> +#include <linux/bitops.h> +#else +#define BIT(nr) (1UL << (nr)) +#endif + +#define COMPDEV_DEFAULT_DEVICE_PREFIX "comp" + + +enum compdev_fmt { + COMPDEV_FMT_RGB565, + COMPDEV_FMT_RGB888, + COMPDEV_FMT_RGBX8888, + COMPDEV_FMT_RGBA8888, + COMPDEV_FMT_YUV422, + COMPDEV_FMT_YCBCR42XMBN, + COMPDEV_FMT_YUV420_SP, + COMPDEV_FMT_YVU420_SP, + COMPDEV_FMT_YUV420_P, +}; + +struct compdev_size { + __u16 width; + __u16 height; +}; + +/* Display rotation */ +enum compdev_rotation { + COMPDEV_ROT_0 = 0, + COMPDEV_ROT_90_CCW = 90, + COMPDEV_ROT_180 = 180, + COMPDEV_ROT_270_CCW = 270, + COMPDEV_ROT_90_CW = COMPDEV_ROT_270_CCW, + COMPDEV_ROT_270_CW = COMPDEV_ROT_90_CCW, +}; + +enum compdev_flag { + COMPDEV_NO_FLAG = 0x00, + COMPDEV_OVERLAY_FLAG = 0x01, + COMPDEV_FRAMEBUFFER_FLAG = 0x02, + COMPDEV_BYPASS_FLAG = 0x04, + COMPDEV_EXTERNAL_DISP_FLAG = 0x08, + COMPDEV_PROTECTED_FLAG = 0x0F, +}; + +enum compdev_ptr_type { + COMPDEV_PTR_PHYSICAL, + COMPDEV_PTR_HWMEM_BUF_NAME_OFFSET, +}; + +enum compdev_listener_state { + COMPDEV_LISTENER_OFF, + COMPDEV_LISTENER_ON, +}; + + +struct compdev_rect { + __s16 x; + __s16 y; + __u16 width; + __u16 height; +}; + +struct compdev_buf { + enum compdev_ptr_type type; + __s32 hwmem_buf_name; + __s32 fd; + __u32 offset; + __u32 len; +}; + +struct compdev_img { + enum compdev_fmt fmt; + struct compdev_buf buf; + __u16 width; + __u16 height; + __u16 pitch; + __u8 z_position; + struct compdev_rect dst_rect; + struct compdev_rect src_rect; + enum compdev_rotation rotation; + __u32 flags; +}; + +struct compdev_scene_info { + enum compdev_rotation ovly_rotation; + enum compdev_rotation fb_rotation; + __u8 img_count; +}; + + +#define COMPDEV_GET_SIZE_IOC _IOR('D', 1, struct compdev_size) +#define COMPDEV_POST_BUFFER_IOC _IOW('D', 2, struct compdev_img) +#define COMPDEV_POST_SCENE_INFO_IOC _IOW('D', 3, struct compdev_scene_info) +#define COMPDEV_GET_LISTENER_STATE_IOC _IOR('D', 4, enum compdev_listener_state) + + +#if defined(__KERNEL__) || defined(_KERNEL) + +#define MAX_NBR_OF_COMPDEVS 2 + +struct compdev; +typedef void (*post_buffer_callback)(void *data, struct compdev_img *img); +typedef void (*post_scene_info_callback)(void *data, + struct compdev_scene_info *s_info); + + +int compdev_create(struct mcde_display_device *ddev, + struct mcde_overlay *parent_ovly, + bool mcde_rotation); +void compdev_destroy(struct mcde_display_device *ddev); + +int compdev_get(int dev_idx, struct compdev **dev); +int compdev_put(struct compdev *dev); +int compdev_get_size(struct compdev *dev, struct compdev_size *size); +int compdev_post_buffer(struct compdev *dev, struct compdev_img *img); +int compdev_post_scene_info(struct compdev *dev, + struct compdev_scene_info *s_info); +int compdev_get_listener_state(struct compdev *dev, + enum compdev_listener_state *listener_state); + +int compdev_register_listener_callbacks(struct compdev *dev, void *data, + post_buffer_callback pb_cb, post_scene_info_callback si_cb); +int compdev_deregister_callbacks(struct compdev *dev); + +#endif /* __KERNEL__ */ + +#endif /* _COMPDEV_H_ */ + diff --git a/include/linux/dispdev.h b/include/linux/dispdev.h new file mode 100644 index 00000000000..cbcf6705150 --- /dev/null +++ b/include/linux/dispdev.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) ST-Ericsson SA 2011 + * + * ST-Ericsson Display device driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef _DISPDEV_H_ +#define _DISPDEV_H_ + +#if !defined(__KERNEL__) && !defined(_KERNEL) +#include <stdint.h> +#else +#include <linux/types.h> +#include <video/mcde.h> +#endif + +#define DISPDEV_DEFAULT_DEVICE_PREFIX "disp" + +enum dispdev_fmt { + DISPDEV_FMT_RGB565, + DISPDEV_FMT_RGB888, + DISPDEV_FMT_RGBX8888, + DISPDEV_FMT_RGBA8888, + DISPDEV_FMT_YUV422, +}; + +struct dispdev_config { + uint16_t format; + uint16_t stride; + uint16_t x; + uint16_t y; + uint16_t z; + uint16_t width; + uint16_t height; + + uint32_t user_flags; +}; + +struct dispdev_buffer_info { + uint16_t buf_idx; + uint16_t display_update; + struct dispdev_config buf_cfg; +}; + +#define DISPDEV_SET_CONFIG_IOC _IOW('D', 1, struct dispdev_config) +#define DISPDEV_GET_CONFIG_IOC _IOR('D', 2, struct dispdev_config) +#define DISPDEV_REGISTER_BUFFER_IOC _IO('D', 3) +#define DISPDEV_UNREGISTER_BUFFER_IOC _IO('D', 4) +#define DISPDEV_QUEUE_BUFFER_IOC _IOW('D', 5, struct dispdev_buffer_info) +#define DISPDEV_DEQUEUE_BUFFER_IOC _IO('D', 6) + +#ifdef __KERNEL__ + +int dispdev_create(struct mcde_display_device *ddev, bool overlay, + struct mcde_overlay *parent_ovly); +void dispdev_destroy(struct mcde_display_device *ddev); + +#endif /* __KERNEL__ */ + +#endif /* _DISPDEV_H_ */ + diff --git a/include/video/Kbuild b/include/video/Kbuild index ad3e622c533..d73b95df921 100644 --- a/include/video/Kbuild +++ b/include/video/Kbuild @@ -1,3 +1,4 @@ +header-y += b2r2_blt.h header-y += edid.h header-y += sisfb.h header-y += uvesafb.h diff --git a/include/video/av8100.h b/include/video/av8100.h new file mode 100644 index 00000000000..23e96a0b871 --- /dev/null +++ b/include/video/av8100.h @@ -0,0 +1,549 @@ +/* + * 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. + */ +#ifndef __AV8100__H__ +#define __AV8100__H__ + +#define AV8100_CEC_MESSAGE_SIZE 16 +#define AV8100_HDCP_SEND_KEY_SIZE 16 +#define AV8100_INFOFRAME_SIZE 28 +#define AV8100_FUSE_KEY_SIZE 16 +#define AV8100_CHIPVER_1 1 +#define AV8100_CHIPVER_2 2 + +struct av8100_platform_data { + unsigned gpio_base; + int irq; + int reset; + const char *inputclk_id; + const char *regulator_pwr_id; + bool alt_powerupseq; + unsigned char mclk_freq; +}; + +enum av8100_command_type { + AV8100_COMMAND_VIDEO_INPUT_FORMAT = 0x1, + AV8100_COMMAND_AUDIO_INPUT_FORMAT, + AV8100_COMMAND_VIDEO_OUTPUT_FORMAT, + AV8100_COMMAND_VIDEO_SCALING_FORMAT, + AV8100_COMMAND_COLORSPACECONVERSION, + AV8100_COMMAND_CEC_MESSAGE_WRITE, + AV8100_COMMAND_CEC_MESSAGE_READ_BACK, + AV8100_COMMAND_DENC, + AV8100_COMMAND_HDMI, + AV8100_COMMAND_HDCP_SENDKEY, + AV8100_COMMAND_HDCP_MANAGEMENT, + AV8100_COMMAND_INFOFRAMES, + AV8100_COMMAND_EDID_SECTION_READBACK, + AV8100_COMMAND_PATTERNGENERATOR, + AV8100_COMMAND_FUSE_AES_KEY, +}; + +enum interface_type { + I2C_INTERFACE = 0x0, + DSI_INTERFACE = 0x1, +}; + +enum av8100_dsi_mode { + AV8100_HDMI_DSI_OFF, + AV8100_HDMI_DSI_COMMAND_MODE, + AV8100_HDMI_DSI_VIDEO_MODE +}; + +enum av8100_pixel_format { + AV8100_INPUT_PIX_RGB565, + AV8100_INPUT_PIX_RGB666, + AV8100_INPUT_PIX_RGB666P, + AV8100_INPUT_PIX_RGB888, + AV8100_INPUT_PIX_YCBCR422 +}; + +enum av8100_video_mode { + AV8100_VIDEO_INTERLACE, + AV8100_VIDEO_PROGRESSIVE +}; + +enum av8100_dsi_nb_data_lane { + AV8100_DATA_LANES_USED_0, + AV8100_DATA_LANES_USED_1, + AV8100_DATA_LANES_USED_2, + AV8100_DATA_LANES_USED_3, + AV8100_DATA_LANES_USED_4 +}; + +enum av8100_te_config { + AV8100_TE_OFF, /* NO TE*/ + AV8100_TE_DSI_LANE, /* TE generated on DSI lane */ + AV8100_TE_IT_LINE, /* TE generated on IT line (GPIO) */ + AV8100_TE_DSI_IT, /* TE generatedon both DSI lane & IT line*/ + AV8100_TE_GPIO_IT /* TE on GPIO I2S DAT3 & or IT line*/ +}; + +enum av8100_audio_if_format { + AV8100_AUDIO_I2S_MODE, + AV8100_AUDIO_I2SDELAYED_MODE, /* I2S Mode by default*/ + AV8100_AUDIO_TDM_MODE /* 8 Channels by default*/ +}; + +enum av8100_sample_freq { + AV8100_AUDIO_FREQ_32KHZ, + AV8100_AUDIO_FREQ_44_1KHZ, + AV8100_AUDIO_FREQ_48KHZ, + AV8100_AUDIO_FREQ_64KHZ, + AV8100_AUDIO_FREQ_88_2KHZ, + AV8100_AUDIO_FREQ_96KHZ, + AV8100_AUDIO_FREQ_128KHZ, + AV8100_AUDIO_FREQ_176_1KHZ, + AV8100_AUDIO_FREQ_192KHZ +}; + +enum av8100_audio_word_length { + AV8100_AUDIO_16BITS, + AV8100_AUDIO_20BITS, + AV8100_AUDIO_24BITS +}; + +enum av8100_audio_format { + AV8100_AUDIO_LPCM_MODE, + AV8100_AUDIO_COMPRESS_MODE +}; + +enum av8100_audio_if_mode { + AV8100_AUDIO_SLAVE, + AV8100_AUDIO_MASTER +}; + +enum av8100_audio_mute { + AV8100_AUDIO_MUTE_DISABLE, + AV8100_AUDIO_MUTE_ENABLE +}; + +enum av8100_output_CEA_VESA { + AV8100_CUSTOM, + AV8100_CEA1_640X480P_59_94HZ, + AV8100_CEA2_3_720X480P_59_94HZ, + AV8100_CEA4_1280X720P_60HZ, + AV8100_CEA5_1920X1080I_60HZ, + AV8100_CEA6_7_NTSC_60HZ, + AV8100_CEA14_15_480p_60HZ, + AV8100_CEA16_1920X1080P_60HZ, + AV8100_CEA17_18_720X576P_50HZ, + AV8100_CEA19_1280X720P_50HZ, + AV8100_CEA20_1920X1080I_50HZ, + AV8100_CEA21_22_576I_PAL_50HZ, + AV8100_CEA29_30_576P_50HZ, + AV8100_CEA31_1920x1080P_50Hz, + AV8100_CEA32_1920X1080P_24HZ, + AV8100_CEA33_1920X1080P_25HZ, + AV8100_CEA34_1920X1080P_30HZ, + AV8100_CEA60_1280X720P_24HZ, + AV8100_CEA61_1280X720P_25HZ, + AV8100_CEA62_1280X720P_30HZ, + AV8100_VESA9_800X600P_60_32HZ, + AV8100_VESA14_848X480P_60HZ, + AV8100_VESA16_1024X768P_60HZ, + AV8100_VESA22_1280X768P_59_99HZ, + AV8100_VESA23_1280X768P_59_87HZ, + AV8100_VESA27_1280X800P_59_91HZ, + AV8100_VESA28_1280X800P_59_81HZ, + AV8100_VESA39_1360X768P_60_02HZ, + AV8100_VESA81_1366X768P_59_79HZ, + AV8100_VIDEO_OUTPUT_CEA_VESA_MAX +}; + +enum av8100_video_sync_pol { + AV8100_SYNC_POSITIVE, + AV8100_SYNC_NEGATIVE +}; + +enum av8100_hdmi_mode { + AV8100_HDMI_OFF, + AV8100_HDMI_ON, + AV8100_HDMI_AVMUTE +}; + +enum av8100_hdmi_format { + AV8100_HDMI, + AV8100_DVI +}; + +enum av8100_DVI_format { + AV8100_DVI_CTRL_CTL0, + AV8100_DVI_CTRL_CTL1, + AV8100_DVI_CTRL_CTL2 +}; + +enum av8100_pattern_type { + AV8100_PATTERN_OFF, + AV8100_PATTERN_GENERATOR, + AV8100_PRODUCTION_TESTING +}; + +enum av8100_pattern_format { + AV8100_NO_PATTERN, + AV8100_PATTERN_VGA, + AV8100_PATTERN_720P, + AV8100_PATTERN_1080P +}; + +enum av8100_pattern_audio { + AV8100_PATTERN_AUDIO_OFF, + AV8100_PATTERN_AUDIO_ON, + AV8100_PATTERN_AUDIO_I2S_MEM +}; + +struct av8100_video_input_format_cmd { + enum av8100_dsi_mode dsi_input_mode; + enum av8100_pixel_format input_pixel_format; + unsigned short total_horizontal_pixel; + unsigned short total_horizontal_active_pixel; + unsigned short total_vertical_lines; + unsigned short total_vertical_active_lines; + enum av8100_video_mode video_mode; + enum av8100_dsi_nb_data_lane nb_data_lane; + unsigned char nb_virtual_ch_command_mode; + unsigned char nb_virtual_ch_video_mode; + unsigned short TE_line_nb; + enum av8100_te_config TE_config; + unsigned long master_clock_freq; + unsigned char ui_x4; +}; + +struct av8100_audio_input_format_cmd { + enum av8100_audio_if_format audio_input_if_format; + unsigned char i2s_input_nb; + enum av8100_sample_freq sample_audio_freq; + enum av8100_audio_word_length audio_word_lg; + enum av8100_audio_format audio_format; + enum av8100_audio_if_mode audio_if_mode; + enum av8100_audio_mute audio_mute; +}; + +struct av8100_video_output_format_cmd { + enum av8100_output_CEA_VESA video_output_cea_vesa; + enum av8100_video_sync_pol vsync_polarity; + enum av8100_video_sync_pol hsync_polarity; + unsigned short total_horizontal_pixel; + unsigned short total_horizontal_active_pixel; + unsigned short total_vertical_in_half_lines; + unsigned short total_vertical_active_in_half_lines; + unsigned short hsync_start_in_pixel; + unsigned short hsync_length_in_pixel; + unsigned short vsync_start_in_half_line; + unsigned short vsync_length_in_half_line; + unsigned short hor_video_start_pixel; + unsigned short vert_video_start_pixel; + enum av8100_video_mode video_type; + unsigned short pixel_repeat; + unsigned long pixel_clock_freq_Hz; +}; + +struct av8100_video_scaling_format_cmd { + unsigned short h_start_in_pixel; + unsigned short h_stop_in_pixel; + unsigned short v_start_in_line; + unsigned short v_stop_in_line; + unsigned short h_start_out_pixel; + unsigned short h_stop_out_pixel; + unsigned short v_start_out_line; + unsigned short v_stop_out_line; +}; + +enum av8100_color_transform { + AV8100_COLOR_TRANSFORM_INDENTITY, + AV8100_COLOR_TRANSFORM_INDENTITY_CLAMP_YUV, + AV8100_COLOR_TRANSFORM_YUV_TO_RGB, + AV8100_COLOR_TRANSFORM_YUV_TO_DENC, + AV8100_COLOR_TRANSFORM_RGB_TO_DENC, +}; + +struct av8100_cec_message_write_format_cmd { + unsigned char buffer_length; + unsigned char buffer[AV8100_CEC_MESSAGE_SIZE]; +}; + +struct av8100_cec_message_read_back_format_cmd { +}; + +enum av8100_cvbs_video_format { + AV8100_CVBS_625, + AV8100_CVBS_525, +}; + +enum av8100_standard_selection { + AV8100_PAL_BDGHI, + AV8100_PAL_N, + AV8100_NTSC_M, + AV8100_PAL_M +}; + +struct av8100_denc_format_cmd { + enum av8100_cvbs_video_format cvbs_video_format; + enum av8100_standard_selection standard_selection; + unsigned char enable; + unsigned char macrovision_enable; + unsigned char internal_generator; +}; + +struct av8100_hdmi_cmd { + enum av8100_hdmi_mode hdmi_mode; + enum av8100_hdmi_format hdmi_format; + enum av8100_DVI_format dvi_format; /* used only if HDMI_format = DVI*/ +}; + +struct av8100_hdcp_send_key_format_cmd { + unsigned char key_number; + unsigned char data_len; + unsigned char data[AV8100_HDCP_SEND_KEY_SIZE]; +}; + +enum av8100_hdcp_auth_req_type { + AV8100_HDCP_AUTH_REQ_OFF = 0, + AV8100_HDCP_AUTH_REQ_ON = 1, + AV8100_HDCP_REV_LIST_REQ = 2, + AV8100_HDCP_AUTH_CONT = 3, +}; + +enum av8100_hdcp_encr_use { + AV8100_HDCP_ENCR_USE_OESS = 0, + AV8100_HDCP_ENCR_USE_EESS = 1, +}; + +struct av8100_hdcp_management_format_cmd { + unsigned char req_type; + unsigned char encr_use; +}; + +struct av8100_infoframes_format_cmd { + unsigned char type; + unsigned char version; + unsigned char length; + unsigned char crc; + unsigned char data[AV8100_INFOFRAME_SIZE]; +}; + +struct av8100_edid_section_readback_format_cmd { + unsigned char address; + unsigned char block_number; +}; + +struct av8100_pattern_generator_format_cmd { + enum av8100_pattern_type pattern_type; + enum av8100_pattern_format pattern_video_format; + enum av8100_pattern_audio pattern_audio_mode; +}; + +enum av8100_fuse_operation { + AV8100_FUSE_READ = 0, + AV8100_FUSE_WRITE = 1, +}; + +struct av8100_fuse_aes_key_format_cmd { + unsigned char fuse_operation; + unsigned char key[AV8100_FUSE_KEY_SIZE]; +}; + +union av8100_configuration { + struct av8100_video_input_format_cmd video_input_format; + struct av8100_audio_input_format_cmd audio_input_format; + struct av8100_video_output_format_cmd video_output_format; + struct av8100_video_scaling_format_cmd video_scaling_format; + enum av8100_color_transform color_transform; + struct av8100_cec_message_write_format_cmd + cec_message_write_format; + struct av8100_cec_message_read_back_format_cmd + cec_message_read_back_format; + struct av8100_denc_format_cmd denc_format; + struct av8100_hdmi_cmd hdmi_format; + struct av8100_hdcp_send_key_format_cmd hdcp_send_key_format; + struct av8100_hdcp_management_format_cmd hdcp_management_format; + struct av8100_infoframes_format_cmd infoframes_format; + struct av8100_edid_section_readback_format_cmd + edid_section_readback_format; + struct av8100_pattern_generator_format_cmd pattern_generator_format; + struct av8100_fuse_aes_key_format_cmd fuse_aes_key_format; +}; + +enum av8100_operating_mode { + AV8100_OPMODE_UNDEFINED = 0, + AV8100_OPMODE_SHUTDOWN, + AV8100_OPMODE_STANDBY, + AV8100_OPMODE_SCAN, + AV8100_OPMODE_INIT, + AV8100_OPMODE_IDLE, + AV8100_OPMODE_VIDEO, +}; + +enum av8100_plugin_status { + AV8100_PLUGIN_NONE = 0x0, + AV8100_HDMI_PLUGIN = 0x1, + AV8100_CVBS_PLUGIN = 0x2, +}; + +enum av8100_hdmi_event { + AV8100_HDMI_EVENT_NONE = 0x0, + AV8100_HDMI_EVENT_HDMI_PLUGIN = 0x1, + AV8100_HDMI_EVENT_HDMI_PLUGOUT = 0x2, + AV8100_HDMI_EVENT_CEC = 0x4, + AV8100_HDMI_EVENT_HDCP = 0x8, + AV8100_HDMI_EVENT_CECTXERR = 0x10, + AV8100_HDMI_EVENT_CECTX = 0x20, /* Transm no error */ +}; + +struct av8100_status { + enum av8100_operating_mode av8100_state; + enum av8100_plugin_status av8100_plugin_status; + int hdmi_on; +}; + + +int av8100_init(void); +void av8100_exit(void); +int av8100_powerscan(void); +int av8100_powerup(void); +int av8100_powerdown(void); +int av8100_disable_interrupt(void); +int av8100_enable_interrupt(void); +int av8100_download_firmware(enum interface_type if_type); +int av8100_reg_stby_w( + unsigned char cpd, + unsigned char stby, + unsigned char mclkrng); +int av8100_reg_hdmi_5_volt_time_w( + unsigned char denc_off_time, + unsigned char hdmi_off_time, + unsigned char on_time); +int av8100_reg_stby_int_mask_w( + unsigned char hpdm, + unsigned char cpdm, + unsigned char stbygpiocfg, + unsigned char ipol); +int av8100_reg_stby_pend_int_w( + unsigned char hpdi, + unsigned char cpdi, + unsigned char oni, + unsigned char bpdig); +int av8100_reg_gen_int_mask_w( + unsigned char eocm, + unsigned char vsim, + unsigned char vsom, + unsigned char cecm, + unsigned char hdcpm, + unsigned char uovbm, + unsigned char tem); +int av8100_reg_gen_int_w( + unsigned char eoci, + unsigned char vsii, + unsigned char vsoi, + unsigned char ceci, + unsigned char hdcpi, + unsigned char uovbi); +int av8100_reg_gpio_conf_w( + unsigned char dat3dir, + unsigned char dat3val, + unsigned char dat2dir, + unsigned char dat2val, + unsigned char dat1dir, + unsigned char dat1val, + unsigned char ucdbg); +int av8100_reg_gen_ctrl_w( + unsigned char fdl, + unsigned char hld, + unsigned char wa, + unsigned char ra); +int av8100_reg_fw_dl_entry_w( + unsigned char mbyte_code_entry); +int av8100_reg_w( + unsigned char offset, + unsigned char value); +int av8100_reg_stby_r( + unsigned char *cpd, + unsigned char *stby, + unsigned char *hpds, + unsigned char *cpds, + unsigned char *mclkrng); +int av8100_reg_hdmi_5_volt_time_r( + unsigned char *denc_off_time, + unsigned char *hdmi_off_time, + unsigned char *on_time); +int av8100_reg_stby_int_mask_r( + unsigned char *hpdm, + unsigned char *cpdm, + unsigned char *stbygpiocfg, + unsigned char *ipol); +int av8100_reg_stby_pend_int_r( + unsigned char *hpdi, + unsigned char *cpdi, + unsigned char *oni, + unsigned char *sid); +int av8100_reg_gen_int_mask_r( + unsigned char *eocm, + unsigned char *vsim, + unsigned char *vsom, + unsigned char *cecm, + unsigned char *hdcpm, + unsigned char *uovbm, + unsigned char *tem); +int av8100_reg_gen_int_r( + unsigned char *eoci, + unsigned char *vsii, + unsigned char *vsoi, + unsigned char *ceci, + unsigned char *hdcpi, + unsigned char *uovbi, + unsigned char *tei); +int av8100_reg_gen_status_r( + unsigned char *cectxerr, + unsigned char *cecrec, + unsigned char *cectrx, + unsigned char *uc, + unsigned char *onuvb, + unsigned char *hdcps); +int av8100_reg_gpio_conf_r( + unsigned char *dat3dir, + unsigned char *dat3val, + unsigned char *dat2dir, + unsigned char *dat2val, + unsigned char *dat1dir, + unsigned char *dat1val, + unsigned char *ucdbg); +int av8100_reg_gen_ctrl_r( + unsigned char *fdl, + unsigned char *hld, + unsigned char *wa, + unsigned char *ra); +int av8100_reg_fw_dl_entry_r( + unsigned char *mbyte_code_entry); +int av8100_reg_r( + unsigned char offset, + unsigned char *value); +int av8100_conf_get(enum av8100_command_type command_type, + union av8100_configuration *config); +int av8100_conf_prep(enum av8100_command_type command_type, + union av8100_configuration *config); +int av8100_conf_w(enum av8100_command_type command_type, + unsigned char *return_buffer_length, + unsigned char *return_buffer, enum interface_type if_type); +int av8100_conf_w_raw(enum av8100_command_type command_type, + unsigned char buffer_length, + unsigned char *buffer, + unsigned char *return_buffer_length, + unsigned char *return_buffer); +struct av8100_status av8100_status_get(void); +enum av8100_output_CEA_VESA av8100_video_output_format_get(int xres, + int yres, + int htot, + int vtot, + int pixelclk, + bool interlaced); +void av8100_hdmi_event_cb_set(void (*event_callback)(enum av8100_hdmi_event)); +u8 av8100_ver_get(void); + +#endif /* __AV8100__H__ */ diff --git a/include/video/b2r2_blt.h b/include/video/b2r2_blt.h new file mode 100644 index 00000000000..4fdc40ab3b9 --- /dev/null +++ b/include/video/b2r2_blt.h @@ -0,0 +1,690 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson B2R2 user interface + * + * Author: Robert Fekete <robert.fekete@stericsson.com> + * Author: Paul Wannback + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + + +#ifndef _LINUX_VIDEO_B2R2_BLT_H +#define _LINUX_VIDEO_B2R2_BLT_H + +#include <linux/types.h> + +#if defined(__KERNEL__) +#include <linux/mm_types.h> +#include <linux/bitops.h> +#else +#define BIT(nr) (1UL << (nr)) +#endif + +/** + * struct b2r2_blt_rect - Specifies a B2R2 rectangle + * + * @left: X-coordinate of top left corner + * @top: Y-coordinate of top left corner + * @width: Rectangle width. Must be >= 0. + * @height: Rectangle height. Must be >= 0. + */ +struct b2r2_blt_rect { + __s32 x; + __s32 y; + __s32 width; + __s32 height; +}; + +/** + * enum b2r2_blt_fmt - Defines the available B2R2 buffer formats + * + * Inspired by Khronos OpenMAX, please see + * OpenMAX IL specification for detailed descriptions of the formats + * + * @B2R2_BLT_FMT_UNUSED: Placeholder value when format is unknown, + * or specified using a vendor-specific means. + * @B2R2_BLT_FMT_16_BIT_ARGB4444: 16 bits per pixel ARGB format with colors + * stored as Alpha 15:12, Red 11:8, Green 7:4, and Blue 3:0. + * @B2R2_BLT_FMT_16_BIT_ARGB1555: 16 bits per pixel ARGB format with colors + * stored as Alpha 15, Red 14:10, Green 9:5, and Blue 4:0. + * @B2R2_BLT_FMT_16_BIT_RGB565: 16 bits per pixel RGB format with colors + * stored as Red 15:11, Green 10:5, and Blue 4:0. + * @B2R2_BLT_FMT_24_BIT_RGB888: 24 bits per pixel RGB format with colors + * stored as Red 23:16, Green 15:8, and Blue 7:0. + * @B2R2_BLT_FMT_32_BIT_ARGB8888: 32 bits per pixel ARGB format with colors + * stored as Alpha 31:24, Red 23:16, Green 15:8, and Blue 7:0. + * @B2R2_BLT_FMT_YUV420_PACKED_PLANAR: YUV planar format, organized with + * three separate planes for each color component, namely Y, U, and V. + * U and V pixels are sub-sampled by a factor of two both horizontally and + * vertically. The buffer shall contain a plane of Y, U, and V data in this + * order + * @B2R2_BLT_FMT_YUV422_PACKED_PLANAR: YUV planar format, organized with + * three separate planes for each color component, namely Y, U, and V. + * U and V pixels are subsampled by a factor of two horizontally. + * The buffer shall contain a plane of Y, U, and V data in this order. + * @B2R2_BLT_FMT_Y_CB_Y_CR: 16 bits per pixel YUV interleaved format organized + * as YUYV (i.e., YCbYCr). + * (Corresponds to YUV422 interleaved) + * @B2R2_BLT_FMT_CB_Y_CR_Y: 16 bits per pixel YUV interleaved format organized + * as UYVY (i.e., CbYCrY). + * (Corresponds to YUV422R) + * @B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR: YUV planar format, organized with + * a first plane containing Y pixels, and a second plane containing U and V + * pixels interleaved with the first U value first. U and V pixels are + * sub-sampled by a factor of two both horizontally and vertically. The buffer + * shall contain a plane of Y, U and V data. + * (Same as B2R2 420 Raster 2 buffer - 420 R2B) + * @B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR: YUV planar format, organized with + * a first plane containing Y pixels, and a second plane containing U and V + * pixels interleaved with the first U value first. U and V pixels are + * sub-sampled by a factor of two horizontally. The buffer shall contain a + * plane of Y, U and V data. + * (Same as B2R2 422 Raster 2 buffer - 422 R2B) + * @B2R2_BLT_FMT_32_BIT_ABGR8888: 32 bits per pixel ABGR format with colors + * stored as Alpha 31:24,Blue 23:16, Green 15:8, and Red 7:0. + * @B2R2_BLT_FMT_24_BIT_ARGB8565: 24 bits per pixel ARGB format with colors + * stored as Alpha 23:16, Red 15:11, Green 10:5, and Blue 4:0. + * @B2R2_BLT_FMT_24_BIT_YUV888: 24 bits per pixel YUV format with colors + * stored as Y 23:16, U 15:8, and V 7:0. + * @B2R2_BLT_FMT_32_BIT_AYUV8888: 32 bits per pixel AYUV format with colors + * stored as Alpha 31:24, Y 23:16, U 15:8, and V 7:0. + * @B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE: Nomadik YUV 420 macro block + * format, see B2R2 spec for details + * @B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE: Nomadik YUV 422 macro block + * format, see B2R2 spec for details + * @B2R2_BLT_FMT_1_BIT_A1: 1 bit per pixel A format, 1 bit alpha + * @B2R2_BLT_FMT_8_BIT_A8: 8 bit per pixel A format, 8 bit alpha + * @B2R2_BLT_FMT_YUV444_PACKED_PLANAR: YUV planar format, organized with + * three separate planes, one for each color component, namely Y, U, and V. + * All planes use full resolution, there is no subsampling. + * The buffer shall contain a plane of Y, U, and V data in this order. + * @B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR: YVU planar format, organized with + * a first plane containing Y pixels, and a second plane containing V and U + * pixels interleaved with the first V value first. V and U pixels are + * sub-sampled by a factor of two both horizontally and vertically. The buffer + * shall contain two planes, one plane with Y, and one with V and U data. + * (Same as B2R2 420 Raster 2 buffer - 420 R2B except that chroma order is + * swapped.) + * @B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR: YVU planar format, organized with + * a first plane containing Y pixels, and a second plane containing V and U + * pixels interleaved with the first V value first. V and U pixels are + * sub-sampled by a factor of two horizontally. The buffer shall contain a + * two planes, one with Y, and one with V and U data. + * (Same as B2R2 422 Raster 2 buffer - 422 R2B except that chroma order is + * swapped.) + * @B2R2_BLT_FMT_YVU420_PACKED_PLANAR: YVU planar format, organized with + * three separate planes for each color component, namely Y, V, and U. + * V and U pixels are sub-sampled by a factor of two both horizontally and + * vertically. The buffer shall contain a plane of Y, V, and U data in this + * order. (Same as B2R2_BLT_FMT_YUV420_PACKED_PLANAR except that chroma + * order is swapped.) + * @B2R2_BLT_FMT_YVU422_PACKED_PLANAR: YVU planar format, organized with + * three separate planes for each color component, namely Y, V, and U. + * V and U pixels are subsampled by a factor of two horizontally. + * The buffer shall contain a plane of Y, V, and U data in this order. + * (Same as B2R2_BLT_FMT_YUV422_PACKED_PLANAR except that chroma + * order is swapped.) + * @B2R2_BLT_FMT_24_BIT_VUY888: 24 bits per pixel VUY format with colors + * stored as V 23:16, U 15:8, and Y 7:0. + * @B2R2_BLT_FMT_32_BIT_VUYA8888: 32 bits per pixel VUYA format with colors + * stored as V 31:24, U 23:16, Y 15:8, and Alpha 7:0. + */ +enum b2r2_blt_fmt { + B2R2_BLT_FMT_UNUSED = 0, + B2R2_BLT_FMT_16_BIT_ARGB4444 = 4, + B2R2_BLT_FMT_16_BIT_ARGB1555 = 5, + B2R2_BLT_FMT_16_BIT_RGB565 = 6, + B2R2_BLT_FMT_24_BIT_RGB888 = 11, + B2R2_BLT_FMT_32_BIT_ARGB8888 = 16, + B2R2_BLT_FMT_YUV420_PACKED_PLANAR = 20, + B2R2_BLT_FMT_YUV422_PACKED_PLANAR = 23, + B2R2_BLT_FMT_Y_CB_Y_CR = 25, + B2R2_BLT_FMT_CB_Y_CR_Y = 27, + B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR = 39, + B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR = 40, + /* Extensions, non OpenMAX formats */ + B2R2_BLT_FMT_32_BIT_ABGR8888 = 0x7F000000, /* OpenMax vendor start */ + B2R2_BLT_FMT_24_BIT_ARGB8565 = 0x7F000001, + B2R2_BLT_FMT_24_BIT_YUV888 = 0x7F000002, + B2R2_BLT_FMT_32_BIT_AYUV8888 = 0x7F000003, + B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE = 0x7F000004, + B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE = 0x7F000005, + B2R2_BLT_FMT_1_BIT_A1 = 0x7F000006, + B2R2_BLT_FMT_8_BIT_A8 = 0x7F000007, + B2R2_BLT_FMT_YUV444_PACKED_PLANAR = 0x7F000008, + B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR = 0x7F000009, + B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR = 0x7F00000A, + B2R2_BLT_FMT_YVU420_PACKED_PLANAR = 0x7F00000B, + B2R2_BLT_FMT_YVU422_PACKED_PLANAR = 0x7F00000C, + B2R2_BLT_FMT_24_BIT_VUY888 = 0x7F00000D, + B2R2_BLT_FMT_32_BIT_VUYA8888 = 0x7F00000E, +}; + +/** + * enum b2r2_blt_ptr_type - Specifies a B2R2 buffer pointer type + * + * @B2R2_BLT_PTR_NONE: + * No pointer (NULL). E.g. src fill. + * @B2R2_BLT_PTR_VIRTUAL: + * Use offset as a userspace virtual address + * @B2R2_BLT_PTR_PHYSICAL: + * Use offset as a physical address + * @B2R2_BLT_PTR_FD_OFFSET: + * Use fd + offset to determine buffer location. + * @B2R2_BLT_PTR_HWMEM_BUF_NAME: + * Use hwmem_buf_name and offset to determine buffer location. + */ +enum b2r2_blt_ptr_type { + B2R2_BLT_PTR_NONE, + B2R2_BLT_PTR_VIRTUAL, + B2R2_BLT_PTR_PHYSICAL, + B2R2_BLT_PTR_FD_OFFSET, + B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET, +}; + +/** + * struct b2r2_blt_buf - Specifies a B2R2 buffer pointer + * + * @type: Buffer pointer type + * @hwmem_global_buf_id: Hwmem buffer name + * @fd: File descriptor (e.g. file handle to pmem or fb device) + * @offset: Offset where buffer can be found or address. + * @len: Size of buffer in bytes + * @bits: Pointer to the bitmap data. This field can be used to specify + * an alternative way to access the buffer. Whenever the 'bits' pointer + * is set to non-NULL, the underlying implementation is free to decide + * whether or not to use it in favor of other ways to locate the buffer. + */ +struct b2r2_blt_buf { + enum b2r2_blt_ptr_type type; + __s32 hwmem_buf_name; + __s32 fd; + __u32 offset; + __u32 len; + void *bits; +}; + + +/** + * struct b2r2_blt_img - Specifies a B2R2 image + * + * @fmt: Pixel format of image + * @buf: Pixel buffer + * @width: Width in pixels + * @height: Height in pixels + * @pitch: Pitch in bytes (from start of one line to start of next) + */ +struct b2r2_blt_img { + enum b2r2_blt_fmt fmt; + struct b2r2_blt_buf buf; + __s32 width; + __s32 height; + __u32 pitch; +}; + + +/** + * enum b2r2_blt_transform- Specifies rotation and flipping, mutually exclusive + * @B2R2_BLT_TRANSFORM_NONE: + * No rotation or flip + * @B2R2_BLT_TRANSFORM_FLIP_H + * Flip horizontally + * @B2R2_BLT_TRANSFORM_FLIP_V + * Flip vertically + * @B2R2_BLT_TRANSFORM_CCW_ROT_90 + * Rotate 90 degrees counter clockwise + * @B2R2_BLT_TRANSFORM_CCW_ROT_180 + * Rotate 180 degrees (same as flip horizontally together with + * flip vertically) + * @B2R2_BLT_TRANSFORM_CCW_ROT_270 + * Rotate 270 degrees counter clockwise + * @B2R2_BLT_TRANSFORM_FLIP_H_CCW_ROT_90 + * Flip horizontally and then rotate 90 degrees counter clockwise + * @B2R2_BLT_TRANSFORM_FLIP_V_CCW_ROT_90 + * Flip vertically and then rotate 90 degrees counter clockwise + */ +enum b2r2_blt_transform { + B2R2_BLT_TRANSFORM_NONE = 0, + B2R2_BLT_TRANSFORM_FLIP_H = 1, + B2R2_BLT_TRANSFORM_FLIP_V = 2, + B2R2_BLT_TRANSFORM_CCW_ROT_90 = 4, + B2R2_BLT_TRANSFORM_CCW_ROT_180 = 3, + B2R2_BLT_TRANSFORM_CCW_ROT_270 = 7, + B2R2_BLT_TRANSFORM_FLIP_H_CCW_ROT_90 = 5, + B2R2_BLT_TRANSFORM_FLIP_V_CCW_ROT_90 = 6, +}; + + +/** + * enum b2r2_blt_flag - Flags that controls the B2R2 request + * + * Can be combined. + * + * @B2R2_BLT_FLAG_ASYNCH: + * Asynchronous request. b2r2_blt will returns when the request + * has been queued. + * @B2R2_BLT_FLAG_DRY_RUN: + * Dry run, just to check if request can be performed. + * @B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND: + * Enable per pixel alpha blend + * @B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND: + * Enable global alpha blend (alpha value in global_alpha) + * @B2R2_BLT_FLAG_SOURCE_COLOR_KEY: + * Enable source color key (color in src_color). Color should be in raw + * format. + * B2R2_BLT_FLAG_SOURCE_COLOR_KEY, B2R2_BLT_FLAG_SOURCE_FILL and + * B2R2_BLT_FLAG_SOURCE_FILL_RAW cannot be specified at the same time. + * B2R2_BLT_FLAG_SOURCE_COLOR_KEY and B2R2_BLT_FLAG_DEST_COLOR_KEY cannot be + * specified at the same time. + * @B2R2_BLT_FLAG_SOURCE_FILL: + * Enable ARGB/AYUV source fill (color in src_color). Which of ARGB and AYUV + * is determined by the destination format. + * B2R2_BLT_FLAG_SOURCE_COLOR_KEY, B2R2_BLT_FLAG_SOURCE_FILL and + * B2R2_BLT_FLAG_SOURCE_FILL_RAW cannot be specified at the same time + * @B2R2_BLT_FLAG_SOURCE_FILL_RAW: + * Enable raw color source fill (color in src_color) + * B2R2_BLT_FLAG_SOURCE_COLOR_KEY, B2R2_BLT_FLAG_SOURCE_FILL and + * B2R2_BLT_FLAG_SOURCE_FILL_RAW cannot be specified at the same time + * @B2R2_BLT_FLAG_DEST_COLOR_KEY: + * Enable dest color key (color in dst_color). Color in raw format. + * @B2R2_BLT_FLAG_SRC_IS_NOT_PREMULT: + * Source color not premultiplied (Valid for alpha formats only). + * @B2R2_BLT_FLAG_DITHER: + * Enable dithering + * @B2R2_BLT_FLAG_BLUR: + * Enable blur + * @B2R2_BLT_FLAG_SOURCE_MASK: + * Enable source mask + * @B2R2_BLT_FLAG_DESTINATION_CLIP: + * Enable destination clip rectangle + * @B2R2_BLT_FLAG_INHERIT_PRIO + * Inherit process priority + * @B2R2_BLT_FLAG_SRC_NO_CACHE_FLUSH + * Skip cache flush of source image buffer + * @B2R2_BLT_FLAG_SRC_MASK_NO_CACHE_FLUSH + * Skip cache flush of source mask buffer + * @B2R2_BLT_FLAG_DST_NO_CACHE_FLUSH + * Skip cache flush of destination image buffer + * @B2R2_BLT_FLAG_BG_BLEND + * Indicate that a background buffer is supplied + * to the blit operation. B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND, + * B2R2_BLT_FLAG_SRC_IS_NOT_PREMULT, and + * B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND will control the blend operation. + * The destination blending is in this case disabled and the destination + * buffer will be overwritten with the source and background blend result. + * @B2R2_BLT_FLAG_BG_NO_CACHE_FLUSH + * Skip cache flush of background image buffer + * @B2R2_BLT_FLAG_REPORT_WHEN_DONE + * Report through b2r2_blt file when done. A b2r2_blt_report structure is + * read. Use poll() or select() if anything to read. (i.e. to help user space + * to implement callback functionality) + * @B2R2_BLT_FLAG_REPORT_PERFORMANCE + * Include performance data in the report structure + * @B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION + * Use color look-up table for color correction. + * Pointer to the table must be specified in *clut field of + * the b2r2_blt_req structure. + * The table must map all input color values + * for each channel to the desired output values. + * It is an array with the following format: + * R0 G0 B0 A0 R1 G1 B1 A1...R255 G255 B255 A255 + * where R0 is the 8 bit output value for red channel whenever its input + * equals 0. + * Similarly, R1 through R255 are the red channel outputs whenever + * the channel's inputs equal 1 through 255 respectively. + * Gn, Bn, An denote green, blue and alpha channel. + * Whenever the input bitmap format lacks the alpha channel, + * all alpha values in the color correction table should be set to 255. + * Size of the array that specifies the color correction table + * must be 1024 bytes. + * A table that does not change anything has the form: + * 0 0 0 0 1 1 1 1 2 2 2 2 ... 254 254 254 254 255 255 255 255. + * CLUT color correction can be applied to YUV raster buffers as well, + * in which case the RGB color channels are mapped onto YUV-space + * as follows: + * R = red chrominance + * G = luminance + * B = blue chrominance + * A = alpha + * If any of the planar or semi-planar formats is used, luminance cannot + * be changed by the color correction table. + */ +enum b2r2_blt_flag { + B2R2_BLT_FLAG_ASYNCH = BIT(0),/*0x1*/ + B2R2_BLT_FLAG_DRY_RUN = BIT(1),/*0x2*/ + B2R2_BLT_FLAG_PER_PIXEL_ALPHA_BLEND = BIT(2),/*0x4*/ + B2R2_BLT_FLAG_GLOBAL_ALPHA_BLEND = BIT(3),/*0x8*/ + B2R2_BLT_FLAG_SOURCE_COLOR_KEY = BIT(4),/*0x10*/ + B2R2_BLT_FLAG_SOURCE_FILL = BIT(5),/*0x20*/ + B2R2_BLT_FLAG_SOURCE_FILL_RAW = BIT(6),/*0x40*/ + B2R2_BLT_FLAG_DEST_COLOR_KEY = BIT(7),/*0x80*/ + B2R2_BLT_FLAG_SRC_IS_NOT_PREMULT = BIT(8),/*0x100*/ + B2R2_BLT_FLAG_DITHER = BIT(9),/*0x200*/ + B2R2_BLT_FLAG_BLUR = BIT(10),/*0x400*/ + B2R2_BLT_FLAG_SOURCE_MASK = BIT(11),/*0x800*/ + B2R2_BLT_FLAG_DESTINATION_CLIP = BIT(12),/*0x1000*/ + B2R2_BLT_FLAG_INHERIT_PRIO = BIT(13),/*0x2000*/ + B2R2_BLT_FLAG_SRC_NO_CACHE_FLUSH = BIT(14),/*0x4000*/ + B2R2_BLT_FLAG_SRC_MASK_NO_CACHE_FLUSH = BIT(15),/*0x8000*/ + B2R2_BLT_FLAG_DST_NO_CACHE_FLUSH = BIT(16),/*0x10000*/ + B2R2_BLT_FLAG_BG_BLEND = BIT(17),/*0x20000*/ + B2R2_BLT_FLAG_BG_NO_CACHE_FLUSH = BIT(18),/*0x40000*/ + B2R2_BLT_FLAG_FULL_RANGE_YUV = BIT(19),/*0x20000*/ + B2R2_BLT_FLAG_REPORT_WHEN_DONE = BIT(29),/*0x20000000*/ + B2R2_BLT_FLAG_REPORT_PERFORMANCE = BIT(30),/*0x40000000*/ + B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION = BIT(31),/*0x80000000*/ +}; + + +/** + * struct b2r2_blt_req - Specifies a request to B2R2 + * + * @size: Size of this structure. Used for versioning. MUST be specified. + * @flags: Flags that control the B2R2 request ORed together + * @tfm: How source should be flipped and rotated when blitting + * @prio: Priority (-20 to 19). Inherits process prio + * if B2R2_BLT_FLAG_INHERIT_PRIO. Given priority is mapped onto B2R2. + * TBD: How? + * @clut: Pointer to the look-up table for color correction. + * @src_img: Source image. Not used if source fill. + * @src_mask: Source mask. Not used if source fill. + * @src_rect: Source area to be blitted. + * @src_color: Source fill color or color key + * @bg_img: Background image. + * @bg_rect: Background area to blend with. + * @dst_img: Destination image. + * @dst_rect: Destination area to be blitted to. + * @dst_color: Destination color key + * @dst_clip_rect: Destination clip rectangle. + * @global_alpha: Global alpha value (0 - 255) + * @report1: Data 1 to report back when request is done. + * See struct b2r2_blt_report. + * @report2: Data 2 to report back when request is done. + * See struct b2r2_blt_report. + * + */ +struct b2r2_blt_req { + __u32 size; + enum b2r2_blt_flag flags; + enum b2r2_blt_transform transform; + __s32 prio; + void *clut; + struct b2r2_blt_img src_img; + struct b2r2_blt_img src_mask; + struct b2r2_blt_rect src_rect; + __u32 src_color; + struct b2r2_blt_img bg_img; + struct b2r2_blt_rect bg_rect; + struct b2r2_blt_img dst_img; + struct b2r2_blt_rect dst_rect; + struct b2r2_blt_rect dst_clip_rect; + __u32 dst_color; + __u8 global_alpha; + __u32 report1; + __u32 report2; +}; + +/** + * enum b2r2_blt_cap - Capabilities that can be queried for. + * + * Capabilities can be queried for a specific format or for formats in + * general. To query for capabilities in general, specify BLT_FMT_UNUSED + * as format. + * + * B2R2_BLT_CAP_UNUSED: Unused/unspecified capability + * B2R2_BLT_CAP_FMT_SOURCE: Is format supported as source? + * B2R2_BLT_CAP_FMT_SOURCE_MASK: Is format supported as source mask? + * B2R2_BLT_CAP_FMT_DEST: Is format supported as dest? + * B2R2_BLT_CAP_PER_PIXEL_ALPHA_BLEND: Is per pixel alpha blending supported + * with format as source + * B2R2_BLT_CAP_GLOBAL_ALPHA_BLEND: Is per global alpha blending supported + * with format as source + * B2R2_BLT_CAP_SOURCE_COLOR_KEY: Is source color key supported with format as + * source + * B2R2_BLT_CAP_SOURCE_FILL: Is source fill supported with format as source + * B2R2_BLT_CAP_SOURCE_FILL_RAW: Is source fill raw supported with format as + * dest + * B2R2_BLT_CAP_DEST_COLOR_KEY: Is dest color key supported with format as dest + * B2R2_BLT_CAP_DITHER: Is dithering supported with format as source + * B2R2_BLT_CAP_BLUR: Is blur supported with format as source + * B2R2_BLT_CAP_MINIFICATION_LIMIT: Minification limit (copybit support) + * B2R2_BLT_CAP_MAGNIFICATION_LIMIT: Magnification limit (copybit support) + * B2R2_BLT_CAP_SCALING_FRAC_BITS: Number of scaling fractional bits (copybit + * support) + * B2R2_BLT_CAP_ROTATION_STEP_DEG: Supported rotation step in degrees (copybit + * support) + */ + +enum b2r2_blt_cap { + B2R2_BLT_CAP_UNUSED = 0, + /** + * @brief Is format supported as source. + */ + B2R2_BLT_CAP_FMT_SOURCE, + /** + * @brief Is format supported as source mask + */ + B2R2_BLT_CAP_FMT_SOURCE_MASK, + /** + * @brief Is format supported as destination + */ + B2R2_BLT_CAP_FMT_DEST, + /** + * @brief Is per pixel alpha blending supported with format as source + */ + B2R2_BLT_CAP_PER_PIXEL_ALPHA_BLEND, + /** + * @brief Is global alpha blending supported with format as source + */ + B2R2_BLT_CAP_GLOBAL_ALPHA_BLEND, + /** + * @brief Is source color key supported with format as source + */ + B2R2_BLT_CAP_SOURCE_COLOR_KEY, + /** + * @brief Is source fill supported with format as source + */ + B2R2_BLT_CAP_SOURCE_FILL, + /** + * @brief Is source fill raw supported with format as dest + */ + B2R2_BLT_CAP_SOURCE_FILL_RAW, + /** + * @brief Is dest color key supported with format as dest + */ + B2R2_BLT_CAP_DEST_COLOR_KEY, + /** + * @brief Is dithering supported with format as source + */ + B2R2_BLT_CAP_DITHER, + /** + * @brief Is blur supported with format as source + */ + B2R2_BLT_CAP_BLUR, + /** + * @brief Minification limit (copybit support) + */ + B2R2_BLT_CAP_MINIFICATION_LIMIT, + /** + * @brief Magnification limit (copybit support) + */ + B2R2_BLT_CAP_MAGNIFICATION_LIMIT, + /** + * @brief Number of scaling fractional bits (copybit support) + */ + B2R2_BLT_CAP_SCALING_FRAC_BITS, + /** + * @brief Supported rotation step in degrees (copybit support) + */ + B2R2_BLT_CAP_ROTATION_STEP_DEG, +}; + +/** + * struct b2r2_blt_query_cap - Query B2R2 capabilities + * + * fmt: Format to query capabilities for or BLT_FMT_UNUSED for all + * cap: Capability to query for + * result: Returned capability. Interpretaion of this variable varies + * with the capability queried + */ +struct b2r2_blt_query_cap { + enum b2r2_blt_fmt fmt; + enum b2r2_blt_cap cap; + __u32 result; +}; + +/** + * struct b2r2_blt_report - Report from B2R2 driver back to user space + * + * This structure can be read from B2R2 driver if B2R2_BLT_FLAG_REPORT_WHEN_DONE + * flag was specified when the request was issued. + * + * @request_id: The id for the request, same as reported from blt_request + * @report1: Client data specified in struct blt_request + * @report2: Client data specified in struct blt_request + * @usec_elapsed: Number of microseconds needed to perform this blit + * if B2R2_BLT_FLAG_REPORT_PERFORMANCE was specified when the + * request was issued. + * + */ +struct b2r2_blt_report { + __u32 request_id; + __u32 report1; + __u32 report2; + __u32 usec_elapsed; +}; + +/** + * B2R2 BLT driver is used in the following way: + * + * Obtain a file descriptor to the driver: + * fd = open("/dev/b2r2_blt", O_RDWR); + * + * Issue requests: + * struct b2r2_blt_request blt_request; + * blt_request.size = sizeof(blt_request); + * ... Fill request with data... + * + * request_id = ioctl(fd, B2R2_BLT_IOC, (__u32) &blt_request); + * + * Wait for a request to finish + * ret = ioctl(fd, B2R2_BLT_SYNCH_IOC, (__u32) request_id); + * + * Wait for all requests from this context to finish + * ret = ioctl(fd, B2R2_BLT_SYNCH_IOC, (__u32) 0); + * + * Wait indefinitely for report data from driver: + * pollfd.fd = fd + * pollfd.events = 0xFFFFFFFF; + * pollfd.revents = 0; + * ret = poll(&pollfd, 1, -1); + * + * Read report data from driver + * struct b2r2_blt_report blt_report; + * + * nread = read(fd, &blt_report, sizeof(blt_report)); + * + * Close the driver + * close(fd); + */ + +/* B2R2 BLT IOCTLS */ + +/** + * B2R2_BLT_IOC_MAGIC is ioctl type group for B2R2 driver + */ +#define B2R2_BLT_IOC_MAGIC 0xb2 + +/** + * The B2R2_BLT_IOC ioctl adds a blit request to B2R2. + * + * The ioctl returns when the blit has been performed if not + * asynchronous execution has been specified. If asynchronous, + * control is returned as soon as the request has been queued. + * + * Supplied parameter shall be a pointer to a struct b2r2_blt_req. + * + * Returns an unique request id if >= 0, else a negative error code. + * This request id can be waited for using B2R2_BLT_SYNC_IOC. + * Return values: -ESOMERROR Description of an error + */ +#define B2R2_BLT_IOC _IOW(B2R2_BLT_IOC_MAGIC, 1, struct b2r2_blt_req) + +/** + * The B2R2_BLT_SYNC_IOC waits for all or a specified request to be finished. + * + * Supplied parameter shall be a request id previously returned by + * B2R2_BLT_IOC or 0 for all requests. + * + * Returns 0 if OK, else a negative error code + * Return value: -ESOMERROR Description of an error + */ +#define B2R2_BLT_SYNCH_IOC _IOW(B2R2_BLT_IOC_MAGIC, 2, int) + +/** + * The BLT_QUERY_CAP_IOC returns capability information for all or + * for a certain format + * + * Supplied parameter shall be a pointer to a struct b2r2_blt_query_cap. + * + * @return Returns 0 if OK, else a negative error code + * @retval -ESOMERROR Description of an error + */ +#define B2R2_BLT_QUERY_CAP_IOC _IOWR(B2R2_BLT_IOC_MAGIC, 3, \ + struct b2r2_blt_query_cap) + +/** + * struct b2r2_platform_data - The b2r2 core hardware configuration + * + * @regulator_id: The name of the b2r2 power source + * @clock_id: The name of the b2r2 clock + * + */ +struct b2r2_platform_data { + const char *regulator_id; + const char *clock_id; +}; + +/** + * b2r2_blt_open - Opening a handle for use with the blitter interface + * + * Returns a handle (0 or greater) to a B2R2 blitter intance on success + */ +int b2r2_blt_open(void); + +/** + * b2r2_blt_close - Free the blitter instance and its resources + * + * @handle: The B2R2 BLT instance handle + * + * All active jobs are finished or cancelled and allocated data + * is released. + * + * Returns 0 on success + */ +int b2r2_blt_close(int handle); + +/** + * b2r2_blt_request - Request a blit operation + * + * @handle: The B2R2 BLT instance handle + * + * Returns 0 on success + */ +int b2r2_blt_request(int handle, struct b2r2_blt_req *user_req); + +/** + * b2r2_blt_synch - Wait for all or a specified job + * + * @handle: The B2R2 BLT instance handle + * @request_id: If 0, wait for all requests on this instance to finish. + * Else wait for the request with the given request id to finish. + * + * Returns 0 on success + */ +int b2r2_blt_synch(int handle, int request_id); + +#endif /* #ifdef _LINUX_VIDEO_B2R2_BLT_H */ diff --git a/include/video/hdmi.h b/include/video/hdmi.h new file mode 100644 index 00000000000..55dcd003fcd --- /dev/null +++ b/include/video/hdmi.h @@ -0,0 +1,205 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * + * HDMI driver + * + * Author: Per Persson <per.xb.persson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ +#ifndef __HDMI__H__ +#define __HDMI__H__ + +#define HDMI_RESULT_OK 0 +#define HDMI_RESULT_NOT_OK 1 +#define HDMI_AES_NOT_FUSED 2 +#define HDMI_RESULT_CRC_MISMATCH 3 + +#define HDMI_CEC_READ_MAXSIZE 16 +#define HDMI_CEC_WRITE_MAXSIZE 15 +#define HDMI_INFOFRAME_MAX_SIZE 27 +#define HDMI_HDCP_FUSEAES_KEYSIZE 16 +#define HDMI_HDCP_AES_BLOCK_START 128 +#define HDMI_HDCP_KSV_BLOCK 40 +#define HDMI_HDCP_AES_NR_OF_BLOCKS 18 +#define HDMI_HDCP_AES_KEYSIZE 16 +#define HDMI_HDCP_AES_KSVSIZE 5 +#define HDMI_HDCP_AES_KSVZEROESSIZE 3 +#define HDMI_EDID_DATA_SIZE 128 +#define HDMI_CEC_SIZE 15 +#define HDMI_INFOFR_SIZE 27 +#define HDMI_FUSE_KEYSIZE 16 +#define HDMI_AES_KSVSIZE 5 +#define HDMI_AES_KEYSIZE 288 +#define HDMI_CRC32_SIZE 4 +#define HDMI_HDCPAUTHRESP_SIZE 126 + +#define HDMI_STOREASTEXT_TEXT_SIZE 2 +#define HDMI_STOREASTEXT_BIN_SIZE 1 +#define HDMI_PLUGDETEN_TEXT_SIZE 6 +#define HDMI_PLUGDETEN_BIN_SIZE 3 +#define HDMI_EDIDREAD_TEXT_SIZE 4 +#define HDMI_EDIDREAD_BIN_SIZE 2 +#define HDMI_CECEVEN_TEXT_SIZE 2 +#define HDMI_CECEVEN_BIN_SIZE 1 +#define HDMI_CECSEND_TEXT_SIZE_MAX 37 +#define HDMI_CECSEND_TEXT_SIZE_MIN 6 +#define HDMI_CECSEND_BIN_SIZE_MAX 18 +#define HDMI_CECSEND_BIN_SIZE_MIN 3 +#define HDMI_INFOFRSEND_TEXT_SIZE_MIN 8 +#define HDMI_INFOFRSEND_TEXT_SIZE_MAX 63 +#define HDMI_INFOFRSEND_BIN_SIZE_MIN 4 +#define HDMI_INFOFRSEND_BIN_SIZE_MAX 31 +#define HDMI_HDCPEVEN_TEXT_SIZE 2 +#define HDMI_HDCPEVEN_BIN_SIZE 1 +#define HDMI_HDCP_FUSEAES_TEXT_SIZE 34 +#define HDMI_HDCP_FUSEAES_BIN_SIZE 17 +#define HDMI_HDCP_LOADAES_TEXT_SIZE 594 +#define HDMI_HDCP_LOADAES_BIN_SIZE 297 +#define HDMI_HDCPAUTHENCR_TEXT_SIZE 4 +#define HDMI_HDCPAUTHENCR_BIN_SIZE 2 +#define HDMI_EVCLR_TEXT_SIZE 2 +#define HDMI_EVCLR_BIN_SIZE 1 +#define HDMI_AUDIOCFG_TEXT_SIZE 14 +#define HDMI_AUDIOCFG_BIN_SIZE 7 +#define HDMI_POWERONOFF_TEXT_SIZE 2 +#define HDMI_POWERONOFF_BIN_SIZE 1 + +#define HDMI_IOC_MAGIC 0xcc + +/** IOCTL Operations */ +#define IOC_PLUG_DETECT_ENABLE _IOWR(HDMI_IOC_MAGIC, 1, int) +#define IOC_EDID_READ _IOWR(HDMI_IOC_MAGIC, 2, int) +#define IOC_CEC_EVENT_ENABLE _IOWR(HDMI_IOC_MAGIC, 3, int) +#define IOC_CEC_READ _IOWR(HDMI_IOC_MAGIC, 4, int) +#define IOC_CEC_SEND _IOWR(HDMI_IOC_MAGIC, 5, int) +#define IOC_INFOFRAME_SEND _IOWR(HDMI_IOC_MAGIC, 6, int) +#define IOC_HDCP_EVENT_ENABLE _IOWR(HDMI_IOC_MAGIC, 7, int) +#define IOC_HDCP_CHKAESOTP _IOWR(HDMI_IOC_MAGIC, 8, int) +#define IOC_HDCP_FUSEAES _IOWR(HDMI_IOC_MAGIC, 9, int) +#define IOC_HDCP_LOADAES _IOWR(HDMI_IOC_MAGIC, 10, int) +#define IOC_HDCP_AUTHENCR_REQ _IOWR(HDMI_IOC_MAGIC, 11, int) +#define IOC_HDCP_STATE_GET _IOWR(HDMI_IOC_MAGIC, 12, int) +#define IOC_EVENTS_READ _IOWR(HDMI_IOC_MAGIC, 13, int) +#define IOC_EVENTS_CLEAR _IOWR(HDMI_IOC_MAGIC, 14, int) +#define IOC_AUDIO_CFG _IOWR(HDMI_IOC_MAGIC, 15, int) +#define IOC_PLUG_STATUS _IOWR(HDMI_IOC_MAGIC, 16, int) +#define IOC_POWERONOFF _IOWR(HDMI_IOC_MAGIC, 17, int) +#define IOC_EVENT_WAKEUP _IOWR(HDMI_IOC_MAGIC, 18, int) +#define IOC_POWERSTATE _IOWR(HDMI_IOC_MAGIC, 19, int) + + +/* HDMI driver */ +void hdmi_event(enum av8100_hdmi_event); +int hdmi_init(void); +void hdmi_exit(void); + +enum hdmi_event { + HDMI_EVENT_NONE = 0x0, + HDMI_EVENT_HDMI_PLUGIN = 0x1, + HDMI_EVENT_HDMI_PLUGOUT = 0x2, + HDMI_EVENT_CEC = 0x4, + HDMI_EVENT_HDCP = 0x8, + HDMI_EVENT_CECTXERR = 0x10, + HDMI_EVENT_WAKEUP = 0x20, + HDMI_EVENT_CECTX = 0x40, +}; + +enum hdmi_hdcp_auth_type { + HDMI_HDCP_AUTH_OFF = 0, + HDMI_HDCP_AUTH_START = 1, + HDMI_HDCP_AUTH_REV_LIST_REQ = 2, + HDMI_HDCP_AUTH_CONT = 3, +}; + +enum hdmi_hdcp_encr_type { + HDMI_HDCP_ENCR_OESS = 0, + HDMI_HDCP_ENCR_EESS = 1, +}; + +struct plug_detect { + __u8 hdmi_detect_enable; + __u8 on_time; + __u8 hdmi_off_time; +}; + +struct edid_read { + __u8 address; + __u8 block_nr; + __u8 data_length; + __u8 data[HDMI_EDID_DATA_SIZE]; +}; + +struct cec_rw { + __u8 src; + __u8 dest; + __u8 length; + __u8 data[HDMI_CEC_SIZE]; +}; + +struct info_fr { + __u8 type; + __u8 ver; + __u8 crc; + __u8 length; + __u8 data[HDMI_INFOFR_SIZE]; +}; + +struct hdcp_fuseaes { + __u8 key[HDMI_FUSE_KEYSIZE]; + __u8 crc; + __u8 result; +}; + +struct hdcp_loadaesall { + __u8 key[HDMI_AES_KEYSIZE]; + __u8 ksv[HDMI_AES_KSVSIZE]; + __u8 crc32[HDMI_CRC32_SIZE]; + __u8 result; +}; + + +/* hdcp_authencr resp coding + * + * When encr_type is 2 (request revoc list), the response is given by + * resp_size is != 0 and resp containing the folllowing: + * + * __u8[5] Bksv from sink (not belonging to revocation list) + * __u8 Device count + * Additional output if Nrofdevices > 0: + * __u8[5 * Nrofdevices] Bksv per connected equipment + * __u8[20] SHA signature + * + * Device count coding: + * 0 = a simple receiver is connected + * 0x80 = a repeater is connected without downstream equipment + * 0x81 = a repeater is connected with one downstream equipment + * up to 0x94 = (0x80 + 0x14) a repeater is connected with downstream + * equipment (thus up to 20 connected equipments) + * 1 = repeater without sink equipment connected + * >1 = number of connected equipment on the repeater + * Nrofdevices = Device count & 0x7F (max 20) + * + * Max resp_size is 5 + 1 + 5 * 20 + 20 = 126 bytes + * + */ +struct hdcp_authencr { + __u8 auth_type; + __u8 encr_type; + __u8 result; + __u8 resp_size; + __u8 resp[HDMI_HDCPAUTHRESP_SIZE]; +}; + +struct audio_cfg { + __u8 if_format; + __u8 i2s_entries; + __u8 freq; + __u8 word_length; + __u8 format; + __u8 if_mode; + __u8 mute; +}; + +#endif /* __HDMI__H__ */ diff --git a/include/video/mcde.h b/include/video/mcde.h new file mode 100644 index 00000000000..499ce5cfecc --- /dev/null +++ b/include/video/mcde.h @@ -0,0 +1,400 @@ +/* + * 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__H__ +#define __MCDE__H__ + +/* Physical interface types */ +enum mcde_port_type { + MCDE_PORTTYPE_DSI = 0, + MCDE_PORTTYPE_DPI = 1, +}; + +/* Interface mode */ +enum mcde_port_mode { + MCDE_PORTMODE_CMD = 0, + MCDE_PORTMODE_VID = 1, +}; + +/* MCDE fifos */ +enum mcde_fifo { + MCDE_FIFO_A = 0, + MCDE_FIFO_B = 1, + MCDE_FIFO_C0 = 2, + MCDE_FIFO_C1 = 3, +}; + +/* MCDE channels (pixel pipelines) */ +enum mcde_chnl { + MCDE_CHNL_A = 0, + MCDE_CHNL_B = 1, + MCDE_CHNL_C0 = 2, + MCDE_CHNL_C1 = 3, +}; + +/* Update sync mode */ +enum mcde_sync_src { + MCDE_SYNCSRC_OFF = 0, /* No sync */ + MCDE_SYNCSRC_TE0 = 1, /* MCDE ext TE0 */ + MCDE_SYNCSRC_TE1 = 2, /* MCDE ext TE1 */ + MCDE_SYNCSRC_BTA = 3, /* DSI BTA */ + MCDE_SYNCSRC_TE_POLLING = 4, /* DSI TE_POLLING */ +}; + +/* Frame trig method */ +enum mcde_trig_method { + MCDE_TRIG_HW = 0, /* frame trig from MCDE formatter */ + MCDE_TRIG_SW = 1, /* frame trig from software */ +}; + +/* Interface pixel formats (output) */ +/* +* REVIEW: Define formats +* Add explanatory comments how the formats are ordered in memory +*/ +enum mcde_port_pix_fmt { + /* MIPI standard formats */ + + MCDE_PORTPIXFMT_DPI_16BPP_C1 = 0x21, + MCDE_PORTPIXFMT_DPI_16BPP_C2 = 0x22, + MCDE_PORTPIXFMT_DPI_16BPP_C3 = 0x23, + MCDE_PORTPIXFMT_DPI_18BPP_C1 = 0x24, + MCDE_PORTPIXFMT_DPI_18BPP_C2 = 0x25, + MCDE_PORTPIXFMT_DPI_24BPP = 0x26, + + MCDE_PORTPIXFMT_DSI_16BPP = 0x31, + MCDE_PORTPIXFMT_DSI_18BPP = 0x32, + MCDE_PORTPIXFMT_DSI_18BPP_PACKED = 0x33, + MCDE_PORTPIXFMT_DSI_24BPP = 0x34, + + /* Custom formats */ + MCDE_PORTPIXFMT_DSI_YCBCR422 = 0x40, +}; + +enum mcde_hdmi_sdtv_switch { + HDMI_SWITCH, + SDTV_SWITCH, + DVI_SWITCH +}; + +enum mcde_col_convert { + MCDE_CONVERT_RGB_2_RGB, + MCDE_CONVERT_RGB_2_YCBCR, + MCDE_CONVERT_YCBCR_2_RGB, + MCDE_CONVERT_YCBCR_2_YCBCR, +}; + +struct mcde_col_transform { + u16 matrix[3][3]; + u16 offset[3]; +}; + +/* DSI video mode */ +enum mcde_dsi_vid_mode { + NON_BURST_MODE_WITH_SYNC_EVENT = 0, + /* enables tvg, test video generator */ + NON_BURST_MODE_WITH_SYNC_EVENT_TVG_ENABLED = 1, + BURST_MODE_WITH_SYNC_EVENT = 2, + BURST_MODE_WITH_SYNC_PULSE = 3, +}; + +#define MCDE_PORT_DPI_NO_CLOCK_DIV 0 + +#define DPI_ACT_HIGH_ALL 0 /* all signals are active high */ +#define DPI_ACT_LOW_HSYNC 1 /* horizontal sync signal is active low */ +#define DPI_ACT_LOW_VSYNC 2 /* vertical sync signal is active low */ +#define DPI_ACT_LOW_DATA_ENABLE 4 /* data enable signal is active low */ +#define DPI_ACT_ON_FALLING_EDGE 8 /* drive data on the falling edge of the + * pixel clock + */ + +struct mcde_port { + enum mcde_port_type type; + enum mcde_port_mode mode; + enum mcde_port_pix_fmt pixel_format; + u8 refresh_rate; /* display refresh rate given in Hz */ + u8 ifc; + u8 link; + enum mcde_sync_src sync_src; + enum mcde_trig_method frame_trig; + bool update_auto_trig; + enum mcde_hdmi_sdtv_switch hdmi_sdtv_switch; + union { + struct { + u8 virt_id; + u8 num_data_lanes; + u8 ui; + bool clk_cont; + bool host_eot_gen; + + /* DSI video mode operating modes */ + enum mcde_dsi_vid_mode vid_mode; + + /* + * wakeup_time is the time to perform + * LP->HS on D-PHY. Given in clock + * cycles of byte clock frequency. + */ + u32 vid_wakeup_time; + + u32 hs_freq; + u32 lp_freq; + + /* DSI data lanes are swapped if true */ + bool data_lanes_swap; + } dsi; + struct { + u8 bus_width; + bool tv_mode; + u16 clock_div; /* use 0 or 1 for no clock divider */ + u32 polarity; /* see DPI_ACT_LOW_* definitions */ + u32 lcd_freq; + } dpi; + } phy; +}; + +/* Overlay pixel formats (input) *//* REVIEW: Define byte order */ +enum mcde_ovly_pix_fmt { + MCDE_OVLYPIXFMT_RGB565 = 1, + MCDE_OVLYPIXFMT_RGBA5551 = 2, + MCDE_OVLYPIXFMT_RGBA4444 = 3, + MCDE_OVLYPIXFMT_RGB888 = 4, + MCDE_OVLYPIXFMT_RGBX8888 = 5, + MCDE_OVLYPIXFMT_RGBA8888 = 6, + MCDE_OVLYPIXFMT_YCbCr422 = 7, +}; + +/* Display power modes */ +enum mcde_display_power_mode { + MCDE_DISPLAY_PM_OFF = 0, /* Power off */ + MCDE_DISPLAY_PM_STANDBY = 1, /* DCS sleep mode */ + MCDE_DISPLAY_PM_ON = 2, /* DCS normal mode, display on */ +}; + +/* Display rotation */ +enum mcde_display_rotation { + MCDE_DISPLAY_ROT_0 = 0, + MCDE_DISPLAY_ROT_90_CCW = 90, + MCDE_DISPLAY_ROT_180_CCW = 180, + MCDE_DISPLAY_ROT_270_CCW = 270, + MCDE_DISPLAY_ROT_90_CW = MCDE_DISPLAY_ROT_270_CCW, + MCDE_DISPLAY_ROT_180_CW = MCDE_DISPLAY_ROT_180_CCW, + MCDE_DISPLAY_ROT_270_CW = MCDE_DISPLAY_ROT_90_CCW, +}; + +/* REVIEW: Verify */ +#define MCDE_MIN_WIDTH 16 +#define MCDE_MIN_HEIGHT 16 +#define MCDE_MAX_WIDTH 2048 +#define MCDE_MAX_HEIGHT 2048 +#define MCDE_BUF_START_ALIGMENT 8 +#define MCDE_BUF_LINE_ALIGMENT 8 + +/* Tv-out defines */ +#define MCDE_CONFIG_TVOUT_BACKGROUND_LUMINANCE 0x83 +#define MCDE_CONFIG_TVOUT_BACKGROUND_CHROMINANCE_CB 0x9C +#define MCDE_CONFIG_TVOUT_BACKGROUND_CHROMINANCE_CR 0x2C + +/* In seconds */ +#define MCDE_AUTO_SYNC_WATCHDOG 5 + +/* DSI modes */ +#define DSI_VIDEO_MODE 0 +#define DSI_CMD_MODE 1 + +/* Video mode descriptor */ +struct mcde_video_mode { + u32 xres; + u32 yres; + u32 pixclock; /* pixel clock in ps (pico seconds) */ + u32 hbp; /* horizontal back porch: left margin (excl. hsync) */ + u32 hfp; /* horizontal front porch: right margin (excl. hsync) */ + u32 hsw; /* horizontal sync width */ + u32 vbp; /* vertical back porch: upper margin (excl. vsync) */ + u32 vfp; /* vertical front porch: lower margin (excl. vsync) */ + u32 vsw; /* vertical sync width*/ + bool interlaced; + bool force_update; /* when switching between hdmi and sdtv */ +}; + +struct mcde_rectangle { + u16 x; + u16 y; + u16 w; + u16 h; +}; + +struct mcde_overlay_info { + u32 paddr; + u32 *vaddr; + u16 stride; /* buffer line len in bytes */ + enum mcde_ovly_pix_fmt fmt; + + u16 src_x; + u16 src_y; + u16 dst_x; + u16 dst_y; + u16 dst_z; + u16 w; + u16 h; + struct mcde_rectangle dirty; +}; + +struct mcde_overlay { + struct kobject kobj; + struct list_head list; /* mcde_display_device.ovlys */ + + struct mcde_display_device *ddev; + struct mcde_overlay_info info; + struct mcde_ovly_state *state; +}; + +/* + * Three functions for mapping 8 bits colour channels on 12 bits colour + * channels. The colour channels (ch0, ch1, ch2) can represent (r, g, b) or + * (Y, Cb, Cr) respectively. + */ +struct mcde_palette_table { + u16 (*map_col_ch0)(u8); + u16 (*map_col_ch1)(u8); + u16 (*map_col_ch2)(u8); +}; + +struct mcde_chnl_state; + +struct mcde_chnl_state *mcde_chnl_get(enum mcde_chnl chnl_id, + enum mcde_fifo fifo, const struct mcde_port *port); +int mcde_chnl_set_pixel_format(struct mcde_chnl_state *chnl, + enum mcde_port_pix_fmt pix_fmt); +int mcde_chnl_set_palette(struct mcde_chnl_state *chnl, + struct mcde_palette_table *palette); +void mcde_chnl_set_col_convert(struct mcde_chnl_state *chnl, + struct mcde_col_transform *transform, + enum mcde_col_convert convert); +int mcde_chnl_set_video_mode(struct mcde_chnl_state *chnl, + struct mcde_video_mode *vmode); +/* TODO: Remove rotbuf* parameters when ESRAM allocator is implemented*/ +int mcde_chnl_set_rotation(struct mcde_chnl_state *chnl, + enum mcde_display_rotation rotation); +int mcde_chnl_set_power_mode(struct mcde_chnl_state *chnl, + enum mcde_display_power_mode power_mode); + +int mcde_chnl_apply(struct mcde_chnl_state *chnl); +int mcde_chnl_update(struct mcde_chnl_state *chnl, + struct mcde_rectangle *update_area, + bool tripple_buffer); +void mcde_chnl_put(struct mcde_chnl_state *chnl); + +void mcde_chnl_stop_flow(struct mcde_chnl_state *chnl); + +void mcde_chnl_enable(struct mcde_chnl_state *chnl); +void mcde_chnl_disable(struct mcde_chnl_state *chnl); + +/* MCDE overlay */ +struct mcde_ovly_state; + +struct mcde_ovly_state *mcde_ovly_get(struct mcde_chnl_state *chnl); +void mcde_ovly_set_source_buf(struct mcde_ovly_state *ovly, + u32 paddr); +void mcde_ovly_set_source_info(struct mcde_ovly_state *ovly, + u32 stride, enum mcde_ovly_pix_fmt pix_fmt); +void mcde_ovly_set_source_area(struct mcde_ovly_state *ovly, + u16 x, u16 y, u16 w, u16 h); +void mcde_ovly_set_dest_pos(struct mcde_ovly_state *ovly, + u16 x, u16 y, u8 z); +void mcde_ovly_apply(struct mcde_ovly_state *ovly); +void mcde_ovly_put(struct mcde_ovly_state *ovly); + +/* MCDE dsi */ + +#define DCS_CMD_ENTER_IDLE_MODE 0x39 +#define DCS_CMD_ENTER_INVERT_MODE 0x21 +#define DCS_CMD_ENTER_NORMAL_MODE 0x13 +#define DCS_CMD_ENTER_PARTIAL_MODE 0x12 +#define DCS_CMD_ENTER_SLEEP_MODE 0x10 +#define DCS_CMD_EXIT_IDLE_MODE 0x38 +#define DCS_CMD_EXIT_INVERT_MODE 0x20 +#define DCS_CMD_EXIT_SLEEP_MODE 0x11 +#define DCS_CMD_GET_ADDRESS_MODE 0x0B +#define DCS_CMD_GET_BLUE_CHANNEL 0x08 +#define DCS_CMD_GET_DIAGNOSTIC_RESULT 0x0F +#define DCS_CMD_GET_DISPLAY_MODE 0x0D +#define DCS_CMD_GET_GREEN_CHANNEL 0x07 +#define DCS_CMD_GET_PIXEL_FORMAT 0x0C +#define DCS_CMD_GET_POWER_MODE 0x0A +#define DCS_CMD_GET_RED_CHANNEL 0x06 +#define DCS_CMD_GET_SCANLINE 0x45 +#define DCS_CMD_GET_SIGNAL_MODE 0x0E +#define DCS_CMD_NOP 0x00 +#define DCS_CMD_READ_DDB_CONTINUE 0xA8 +#define DCS_CMD_READ_DDB_START 0xA1 +#define DCS_CMD_READ_MEMORY_CONTINE 0x3E +#define DCS_CMD_READ_MEMORY_START 0x2E +#define DCS_CMD_SET_ADDRESS_MODE 0x36 +#define DCS_CMD_SET_COLUMN_ADDRESS 0x2A +#define DCS_CMD_SET_DISPLAY_OFF 0x28 +#define DCS_CMD_SET_DISPLAY_ON 0x29 +#define DCS_CMD_SET_GAMMA_CURVE 0x26 +#define DCS_CMD_SET_PAGE_ADDRESS 0x2B +#define DCS_CMD_SET_PARTIAL_AREA 0x30 +#define DCS_CMD_SET_PIXEL_FORMAT 0x3A +#define DCS_CMD_SET_SCROLL_AREA 0x33 +#define DCS_CMD_SET_SCROLL_START 0x37 +#define DCS_CMD_SET_TEAR_OFF 0x34 +#define DCS_CMD_SET_TEAR_ON 0x35 +#define DCS_CMD_SET_TEAR_SCANLINE 0x44 +#define DCS_CMD_SOFT_RESET 0x01 +#define DCS_CMD_WRITE_LUT 0x2D +#define DCS_CMD_WRITE_CONTINUE 0x3C +#define DCS_CMD_WRITE_START 0x2C + +#define MCDE_MAX_DCS_READ 4 +#define MCDE_MAX_DSI_DIRECT_CMD_WRITE 15 + +int mcde_dsi_generic_write(struct mcde_chnl_state *chnl, u8* para, int len); +int mcde_dsi_dcs_write(struct mcde_chnl_state *chnl, + u8 cmd, u8 *data, int len); +int mcde_dsi_dcs_read(struct mcde_chnl_state *chnl, + u8 cmd, u32 *data, int *len); +int mcde_dsi_set_max_pkt_size(struct mcde_chnl_state *chnl); + +/* MCDE */ + +/* Driver data */ +#define MCDE_IRQ "MCDE IRQ" +#define MCDE_IO_AREA "MCDE I/O Area" + +struct mcde_platform_data { + /* DPI */ + u8 outmux[5]; /* MCDE_CONF0.OUTMUXx */ + u8 syncmux; /* MCDE_CONF0.SYNCMUXx */ + + /* TODO: Remove once ESRAM allocator is done */ + u32 rotbuf1; + u32 rotbuf2; + u32 rotbufsize; + + const char *regulator_vana_id; + const char *regulator_mcde_epod_id; + const char *regulator_esram_epod_id; + const char *clock_dsi_id; + const char *clock_dsi_lp_id; + const char *clock_dpi_id; + const char *clock_mcde_id; + + int (*platform_set_clocks)(void); + int (*platform_enable_dsipll)(void); + int (*platform_disable_dsipll)(void); +}; + +int mcde_init(void); +void mcde_exit(void); + +#endif /* __MCDE__H__ */ diff --git a/include/video/mcde_display-ab8500.h b/include/video/mcde_display-ab8500.h new file mode 100644 index 00000000000..ffebe62af92 --- /dev/null +++ b/include/video/mcde_display-ab8500.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * AB8500 tvout driver interface + * + * Author: Marcel Tunnissen <marcel.tuennissen@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ +#ifndef __DISPLAY_AB8500__H__ +#define __DISPLAY_AB8500__H__ + +#include <video/mcde.h> + +struct ab8500_display_platform_data { + /* Platform info */ + struct mcde_col_transform *rgb_2_yCbCr_transform; + int nr_regulators; + const char *regulator_id[]; +}; + +#endif /* __DISPLAY_AB8500__H__*/ + diff --git a/include/video/mcde_display-av8100.h b/include/video/mcde_display-av8100.h new file mode 100644 index 00000000000..7c13b49e58f --- /dev/null +++ b/include/video/mcde_display-av8100.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson MCDE HDMI display driver + * + * Author: Per Persson <per-xb-persson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ +#ifndef __DISPLAY_AV8100__H__ +#define __DISPLAY_AV8100__H__ + +#include <linux/regulator/consumer.h> + +#include "mcde_display.h" + +#define GPIO_AV8100_RSTN 196 +#define NATIVE_XRES_HDMI 1280 +#define NATIVE_YRES_HDMI 720 +#define NATIVE_XRES_SDTV 720 +#define NATIVE_YRES_SDTV 576 +#define DISPONOFF_SIZE 6 +#define TIMING_SIZE 2 +#define STAYALIVE_SIZE 1 + +struct mcde_display_hdmi_platform_data { + /* Platform info */ + int reset_gpio; + bool reset_high; + const char *regulator_id; + const char *cvbs_regulator_id; + int reset_delay; /* ms */ + u32 ddb_id; + struct mcde_col_transform *rgb_2_yCbCr_transform; + + /* Driver data */ /* TODO: move to driver data instead */ + bool hdmi_platform_enable; + struct regulator *regulator; +}; + +struct display_driver_data { + struct regulator *cvbs_regulator; + bool cvbs_regulator_enabled; + bool update_port_pixel_format; + const char *fbdevname; + struct mcde_video_mode *video_mode; +}; + +void hdmi_fb_onoff(struct mcde_display_device *ddev, bool enable, + u8 cea, u8 vesa_cea_nr); + +#endif /* __DISPLAY_AV8100__H__ */ diff --git a/include/video/mcde_display-generic_dsi.h b/include/video/mcde_display-generic_dsi.h new file mode 100644 index 00000000000..87ef6baf67a --- /dev/null +++ b/include/video/mcde_display-generic_dsi.h @@ -0,0 +1,35 @@ +/* + * 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. + */ +#ifndef __MCDE_DISPLAY_GENERIC__H__ +#define __MCDE_DISPLAY_GENERIC__H__ + +#include <linux/regulator/consumer.h> + +#include "mcde_display.h" + +struct mcde_display_generic_platform_data { + /* Platform info */ + int reset_gpio; + bool reset_high; + const char *regulator_id; + int reset_delay; /* ms */ + int sleep_out_delay; /* ms */ + u32 ddb_id; + + /* Driver data */ + bool generic_platform_enable; + struct regulator *regulator; + int max_supply_voltage; + int min_supply_voltage; +}; + +#endif /* __MCDE_DISPLAY_GENERIC__H__ */ + diff --git a/include/video/mcde_display-sony_acx424akp_dsi.h b/include/video/mcde_display-sony_acx424akp_dsi.h new file mode 100644 index 00000000000..29fb14a3fdb --- /dev/null +++ b/include/video/mcde_display-sony_acx424akp_dsi.h @@ -0,0 +1,27 @@ +/* + * 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. + */ +#ifndef __MCDE_DISPLAY_SONY_ACX424AKP__H__ +#define __MCDE_DISPLAY_SONY_ACX424AKP__H__ + +enum display_panel_type { + DISPLAY_NONE = 0, + DISPLAY_SONY_ACX424AKP = 0x1b81, + DISPLAY_SONY_ACX424AKP_ID2 = 0x1a81, +}; + +struct mcde_display_sony_acx424akp_platform_data { + /* Platform info */ + int reset_gpio; + enum display_panel_type disp_panel; /* display panel types */ +}; + +#endif /* __MCDE_DISPLAY_SONY_ACX424AKP__H__ */ + diff --git a/include/video/mcde_display-vuib500-dpi.h b/include/video/mcde_display-vuib500-dpi.h new file mode 100644 index 00000000000..94bad83bf97 --- /dev/null +++ b/include/video/mcde_display-vuib500-dpi.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson MCDE DPI display driver + * + * Author: Torbjorn Svensson <torbjorn.x.svensson@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __MCDE_DISPLAY_DPI__H__ +#define __MCDE_DISPLAY_DPI__H__ + +#include <linux/regulator/consumer.h> + +#include "mcde_display.h" + +struct mcde_display_dpi_platform_data { + /* Platform info */ + int reset_gpio; + bool reset_high; + const char *regulator_id; + int reset_delay; + + /* Driver data */ + struct regulator *regulator; + int max_supply_voltage; + int min_supply_voltage; +}; +#endif /* __MCDE_DISPLAY_DPI__H__ */ diff --git a/include/video/mcde_display.h b/include/video/mcde_display.h new file mode 100644 index 00000000000..5130b228d84 --- /dev/null +++ b/include/video/mcde_display.h @@ -0,0 +1,143 @@ +/* + * 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. + */ +#ifndef __MCDE_DISPLAY__H__ +#define __MCDE_DISPLAY__H__ + +#include <linux/device.h> +#include <linux/pm.h> + +#include <video/mcde.h> + +#define UPDATE_FLAG_PIXEL_FORMAT 0x1 +#define UPDATE_FLAG_VIDEO_MODE 0x2 +#define UPDATE_FLAG_ROTATION 0x4 + +struct mcde_display_dsi_platform_data { + int reset_gpio; + int link; +}; + +#define to_mcde_display_device(__dev) \ + container_of((__dev), struct mcde_display_device, dev) + +struct mcde_display_device { + /* MCDE driver static */ + struct device dev; + const char *name; + int id; + struct mcde_port *port; + struct fb_info *fbi; + bool fictive; + + /* MCDE dss driver internal */ + bool initialized; + enum mcde_chnl chnl_id; + enum mcde_fifo fifo; + bool first_update; + struct mutex display_lock; + + bool enabled; + struct mcde_chnl_state *chnl_state; + struct list_head ovlys; + struct mcde_rectangle update_area; + + + /* Display driver internal */ + u16 native_x_res; + u16 native_y_res; + u16 physical_width; + u16 physical_height; + enum mcde_display_power_mode power_mode; + enum mcde_ovly_pix_fmt default_pixel_format; + enum mcde_ovly_pix_fmt pixel_format; + enum mcde_display_rotation rotation; + enum mcde_display_rotation orientation; + struct mcde_video_mode video_mode; + int update_flags; + bool stay_alive; + int check_transparency; + + /* Driver API */ + void (*get_native_resolution)(struct mcde_display_device *dev, + u16 *x_res, u16 *y_res); + enum mcde_ovly_pix_fmt (*get_default_pixel_format)( + struct mcde_display_device *dev); + void (*get_physical_size)(struct mcde_display_device *dev, + u16 *x_size, u16 *y_size); + + int (*set_power_mode)(struct mcde_display_device *dev, + enum mcde_display_power_mode power_mode); + enum mcde_display_power_mode (*get_power_mode)( + struct mcde_display_device *dev); + + int (*try_video_mode)(struct mcde_display_device *dev, + struct mcde_video_mode *video_mode); + int (*set_video_mode)(struct mcde_display_device *dev, + struct mcde_video_mode *video_mode); + void (*get_video_mode)(struct mcde_display_device *dev, + struct mcde_video_mode *video_mode); + int (*set_pixel_format)(struct mcde_display_device *dev, + enum mcde_ovly_pix_fmt pix_fmt); + enum mcde_ovly_pix_fmt (*get_pixel_format)( + struct mcde_display_device *dev); + enum mcde_port_pix_fmt (*get_port_pixel_format)( + struct mcde_display_device *dev); + + int (*set_rotation)(struct mcde_display_device *dev, + enum mcde_display_rotation rotation); + enum mcde_display_rotation (*get_rotation)( + struct mcde_display_device *dev); + + int (*apply_config)(struct mcde_display_device *dev); + int (*invalidate_area)(struct mcde_display_device *dev, + struct mcde_rectangle *area); + int (*update)(struct mcde_display_device *dev, bool tripple_buffer); + int (*on_first_update)(struct mcde_display_device *dev); + int (*platform_enable)(struct mcde_display_device *dev); + int (*platform_disable)(struct mcde_display_device *dev); + int (*ceanr_convert)(struct mcde_display_device *ddev, + u8 cea, u8 vesa_cea_nr, int buffering, + u16 *w, u16 *h, u16 *vw, u16 *vh); +}; + +struct mcde_display_driver { + int (*probe)(struct mcde_display_device *dev); + int (*remove)(struct mcde_display_device *dev); + void (*shutdown)(struct mcde_display_device *dev); + int (*suspend)(struct mcde_display_device *dev, + pm_message_t state); + int (*resume)(struct mcde_display_device *dev); + + struct device_driver driver; +}; + +/* MCDE dsi (Used by MCDE display drivers) */ + +int mcde_display_dsi_dcs_write(struct mcde_display_device *dev, + u8 cmd, u8 *data, int len); +int mcde_display_dsi_dcs_read(struct mcde_display_device *dev, + u8 cmd, u8 *data, int *len); +int mcde_display_dsi_bta_sync(struct mcde_display_device *dev); + +/* MCDE display bus */ + +int mcde_display_driver_register(struct mcde_display_driver *drv); +void mcde_display_driver_unregister(struct mcde_display_driver *drv); +int mcde_display_device_register(struct mcde_display_device *dev); +void mcde_display_device_unregister(struct mcde_display_device *dev); + +void mcde_display_init_device(struct mcde_display_device *dev); + +int mcde_display_init(void); +void mcde_display_exit(void); + +#endif /* __MCDE_DISPLAY__H__ */ + diff --git a/include/video/mcde_dss.h b/include/video/mcde_dss.h new file mode 100644 index 00000000000..efed79ad023 --- /dev/null +++ b/include/video/mcde_dss.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) ST-Ericsson AB 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. + */ +#ifndef __MCDE_DSS__H__ +#define __MCDE_DSS__H__ + +#include <linux/kobject.h> +#include <linux/notifier.h> + +#include "mcde.h" +#include "mcde_display.h" + +/* Public MCDE dss (Used by MCDE fb ioctl & MCDE display sysfs) */ +int mcde_dss_open_channel(struct mcde_display_device *ddev); +void mcde_dss_close_channel(struct mcde_display_device *ddev); +int mcde_dss_enable_display(struct mcde_display_device *ddev); +void mcde_dss_disable_display(struct mcde_display_device *ddev); +int mcde_dss_apply_channel(struct mcde_display_device *ddev); +struct mcde_overlay *mcde_dss_create_overlay(struct mcde_display_device *ddev, + struct mcde_overlay_info *info); +void mcde_dss_destroy_overlay(struct mcde_overlay *ovl); +int mcde_dss_enable_overlay(struct mcde_overlay *ovl); +void mcde_dss_disable_overlay(struct mcde_overlay *ovl); +int mcde_dss_apply_overlay(struct mcde_overlay *ovl, + struct mcde_overlay_info *info); +void mcde_dss_get_overlay_info(struct mcde_overlay *ovly, + struct mcde_overlay_info *info); +int mcde_dss_update_overlay(struct mcde_overlay *ovl, bool tripple_buffer); + +void mcde_dss_get_native_resolution(struct mcde_display_device *ddev, + u16 *x_res, u16 *y_res); +enum mcde_ovl_pix_fmt mcde_dss_get_default_color_format( + struct mcde_display_device *ddev); +void mcde_dss_get_physical_size(struct mcde_display_device *ddev, + u16 *x_size, u16 *y_size); /* mm */ + +int mcde_dss_try_video_mode(struct mcde_display_device *ddev, + struct mcde_video_mode *video_mode); +int mcde_dss_set_video_mode(struct mcde_display_device *ddev, + struct mcde_video_mode *video_mode); +void mcde_dss_get_video_mode(struct mcde_display_device *ddev, + struct mcde_video_mode *video_mode); + +int mcde_dss_set_pixel_format(struct mcde_display_device *ddev, + enum mcde_ovly_pix_fmt pix_fmt); +int mcde_dss_get_pixel_format(struct mcde_display_device *ddev); + +int mcde_dss_set_rotation(struct mcde_display_device *ddev, + enum mcde_display_rotation rotation); +enum mcde_display_rotation mcde_dss_get_rotation( + struct mcde_display_device *ddev); + +int mcde_dss_set_synchronized_update(struct mcde_display_device *ddev, + bool enable); +bool mcde_dss_get_synchronized_update(struct mcde_display_device *ddev); + +/* MCDE dss events */ + +/* A display device and driver has been loaded, probed and bound */ +#define MCDE_DSS_EVENT_DISPLAY_REGISTERED 1 +/* A display device has been removed */ +#define MCDE_DSS_EVENT_DISPLAY_UNREGISTERED 2 + +/* Note! Notifier callback will be called holding the dev sem */ +int mcde_dss_register_notifier(struct notifier_block *nb); +int mcde_dss_unregister_notifier(struct notifier_block *nb); + +/* MCDE dss driver */ + +int mcde_dss_init(void); +void mcde_dss_exit(void); + +#endif /* __MCDE_DSS__H__ */ + diff --git a/include/video/mcde_fb.h b/include/video/mcde_fb.h new file mode 100644 index 00000000000..17556414aa0 --- /dev/null +++ b/include/video/mcde_fb.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * + * ST-Ericsson MCDE display sub system frame buffer driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ +#ifndef __MCDE_FB__H__ +#define __MCDE_FB__H__ + +#include <linux/fb.h> +#include <linux/ioctl.h> +#if !defined(__KERNEL__) && !defined(_KERNEL) +#include <stdint.h> +#else +#include <linux/types.h> +#include <linux/hwmem.h> +#endif + +#ifdef __KERNEL__ +#include "mcde_dss.h" +#ifdef CONFIG_HAS_EARLYSUSPEND +#include <linux/earlysuspend.h> +#endif +#endif + +#define MCDE_GET_BUFFER_NAME_IOC _IO('M', 1) + +#ifdef __KERNEL__ +#define to_mcde_fb(x) ((struct mcde_fb *)(x)->par) + +#define MCDE_FB_MAX_NUM_OVERLAYS 3 + +struct mcde_fb { + int num_ovlys; + struct mcde_overlay *ovlys[MCDE_FB_MAX_NUM_OVERLAYS]; + u32 pseudo_palette[17]; + enum mcde_ovly_pix_fmt pix_fmt; + int id; + struct hwmem_alloc *alloc; + int alloc_name; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif +}; + +/* MCDE fbdev API */ +struct fb_info *mcde_fb_create(struct mcde_display_device *ddev, + uint16_t w, uint16_t h, uint16_t vw, uint16_t vh, + enum mcde_ovly_pix_fmt pix_fmt, uint32_t rotate); + +int mcde_fb_attach_overlay(struct fb_info *fb_info, + struct mcde_overlay *ovl); +void mcde_fb_destroy(struct mcde_display_device *ddev); + +/* MCDE fb driver */ +int mcde_fb_init(void); +void mcde_fb_exit(void); +#endif + +#endif /* __MCDE_FB__H__ */ + |