MLK-11431-1: IPU: forward IPU display drivers to 4.1.y kernel
Forward imx_3.14.y IPU and display drivers to 4.1 kernel. This includes IPU core driver, display driver, LDB and HDMI driver. Signed-off-by: Sandor Yu <R01008@freescale.com>pull/10/head
parent
312f2f4787
commit
4dc795af9e
|
@ -0,0 +1,105 @@
|
|||
* FSL IPUv3 Display/FB
|
||||
|
||||
The FSL IPUv3 is Image Processing Unit version 3, a part of video and graphics
|
||||
subsystem in an application processor. The goal of the IPU is to provide
|
||||
comprehensive support for the flow of data from an image sensor or/and to a
|
||||
display device.
|
||||
|
||||
Two IPU units are on the imx6q SOC while only one IPU unit on the imx6dl SOC.
|
||||
Each IPU unit has two display interfaces.
|
||||
|
||||
Required properties for IPU:
|
||||
- bypass_reset :Bypass reset to avoid display channel being.
|
||||
stopped by probe since it may start to work in bootloader: 0 or 1.
|
||||
- compatible : should be "fsl,imx6q-ipu".
|
||||
- reg : the register address range.
|
||||
- interrupts : the error and sync interrupts request.
|
||||
- clocks : the clock sources that it depends on.
|
||||
- clock-names: the related clock names.
|
||||
- resets : IPU reset specifier. See reset.txt and fsl,imx-src.txt in
|
||||
Documentation/devicetree/bindings/reset/ for details.
|
||||
|
||||
Required properties for fb:
|
||||
- compatible : should be "fsl,mxc_sdc_fb".
|
||||
- disp_dev : display device: "ldb", "lcd", "hdmi", "mipi_dsi".
|
||||
- mode_str : "CLAA-WVGA" for lcd, "TRULY-WVGA" for TRULY mipi_dsi lcd panel,
|
||||
"1920x1080M@60" for hdmi.
|
||||
- default_bpp : default bits per pixel: 8/16/24/32
|
||||
- int_clk : use internal clock as pixel clock: 0 or 1
|
||||
- late_init : to avoid display channel being re-initialized
|
||||
as we've probably setup the channel in bootloader: 0 or 1
|
||||
- interface_pix_fmt : display interface pixel format as below:
|
||||
RGB666 IPU_PIX_FMT_RGB666
|
||||
RGB565 IPU_PIX_FMT_RGB565
|
||||
RGB24 IPU_PIX_FMT_RGB24
|
||||
BGR24 IPU_PIX_FMT_BGR24
|
||||
GBR24 IPU_PIX_FMT_GBR24
|
||||
YUV444 IPU_PIX_FMT_YUV444
|
||||
YUYV IPU_PIX_FMT_YUYV
|
||||
UYVY IPU_PIX_FMT_UYVY
|
||||
YVYV IPU_PIX_FMT_YVYU
|
||||
VYUY IPU_PIX_FMT_VYUY
|
||||
|
||||
Required properties for display:
|
||||
- compatible : should be "fsl,lcd" for lcd panel
|
||||
- reg : the register address range if necessary to have.
|
||||
- interrupts : the error and sync interrupts if necessary to have.
|
||||
- clocks : the clock sources that it depends on if necessary to have.
|
||||
- clock-names: the related clock names if necessary to have.
|
||||
- ipu_id : ipu id for the first display device: 0 or 1
|
||||
- disp_id : display interface id for the first display interface: 0 or 1
|
||||
- default_ifmt : save as above display interface pixel format for lcd
|
||||
- pinctrl-names : should be "default"
|
||||
- pinctrl-0 : should be pinctrl_ipu1_1 or pinctrl_ipu2_1, which depends on the
|
||||
IPU connected.
|
||||
- gpr : the mux controller for the display engine's display interfaces and the display encoder
|
||||
(only valid for mipi dsi now).
|
||||
- disp-power-on-supply : the regulator to control display panel's power.
|
||||
(only valid for mipi dsi now).
|
||||
- resets : the gpio pin to reset the display device(only valid for mipi display panel now).
|
||||
- lcd_panel : the video mode name for the display device(only valid for mipi display panel now).
|
||||
- dev_id : the display engine's identity within the system, which intends to replace ipu_id
|
||||
(only valid for mipi dsi now).
|
||||
|
||||
Example for IPU:
|
||||
ipu1: ipu@02400000 {
|
||||
compatible = "fsl,imx6q-ipu";
|
||||
reg = <0x02400000 0x400000>;
|
||||
interrupts = <0 6 0x4 0 5 0x4>;
|
||||
clocks = <&clks 130>, <&clks 131>, <&clks 132>,
|
||||
<&clks 39>, <&clks 40>,
|
||||
<&clks 135>, <&clks 136>;
|
||||
clock-names = "bus", "di0", "di1",
|
||||
"di0_sel", "di1_sel",
|
||||
"ldb_di0", "ldb_di1";
|
||||
resets = <&src 2>;
|
||||
bypass_reset = <0>;
|
||||
};
|
||||
|
||||
Example for fb:
|
||||
fb0 {
|
||||
compatible = "fsl,mxc_sdc_fb";
|
||||
disp_dev = "ldb";
|
||||
interface_pix_fmt = "RGB666";
|
||||
mode_str ="LDB-XGA";
|
||||
default_bpp = <16>;
|
||||
int_clk = <0>;
|
||||
late_init = <0>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
Example for mipi dsi display:
|
||||
mipi_dsi: mipi@021e0000 {
|
||||
compatible = "fsl,imx6q-mipi-dsi";
|
||||
reg = <0x021e0000 0x4000>;
|
||||
interrupts = <0 102 0x04>;
|
||||
gpr = <&gpr>;
|
||||
clocks = <&clks 138>, <&clks 204>;
|
||||
clock-names = "mipi_pllref_clk", "mipi_cfg_clk";
|
||||
dev_id = <0>;
|
||||
disp_id = <0>;
|
||||
lcd_panel = "TRULY-WVGA";
|
||||
disp-power-on-supply = <®_mipi_dsi_pwr_on>
|
||||
resets = <&mipi_dsi_reset>;
|
||||
status = "okay";
|
||||
};
|
|
@ -394,6 +394,13 @@ config MFD_MX25_TSADC
|
|||
i.MX25 processors. They consist of a conversion queue for general
|
||||
purpose ADC and a queue for Touchscreens.
|
||||
|
||||
config MFD_MXC_HDMI
|
||||
tristate "Freescale HDMI Core"
|
||||
select MFD_CORE
|
||||
help
|
||||
This is the core driver for the Freescale i.MX6 on-chip HDMI.
|
||||
This MFD driver connects with the video and audio drivers for HDMI.
|
||||
|
||||
config MFD_HI6421_PMIC
|
||||
tristate "HiSilicon Hi6421 PMU/Codec IC"
|
||||
depends on OF
|
||||
|
|
|
@ -214,6 +214,7 @@ obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o
|
|||
obj-$(CONFIG_MFD_DLN2) += dln2.o
|
||||
obj-$(CONFIG_MFD_RT5033) += rt5033.o
|
||||
obj-$(CONFIG_MFD_SKY81452) += sky81452.o
|
||||
obj-$(CONFIG_MFD_MXC_HDMI) += mxc-hdmi-core.o
|
||||
|
||||
intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o
|
||||
obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
|
||||
|
|
|
@ -0,0 +1,808 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2015 Freescale Semiconductor, Inc.
|
||||
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
#include <video/mxc_hdmi.h>
|
||||
#include <linux/ipu-v3.h>
|
||||
#include <video/mxc_edid.h>
|
||||
#include "../mxc/ipu3/ipu_prv.h"
|
||||
#include <linux/mfd/mxc-hdmi-core.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/mfd/mxc-hdmi-core.h>
|
||||
|
||||
struct mxc_hdmi_data {
|
||||
struct platform_device *pdev;
|
||||
unsigned long __iomem *reg_base;
|
||||
unsigned long reg_phys_base;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static void __iomem *hdmi_base;
|
||||
static struct clk *isfr_clk;
|
||||
static struct clk *iahb_clk;
|
||||
static struct clk *mipi_core_clk;
|
||||
static spinlock_t irq_spinlock;
|
||||
static spinlock_t edid_spinlock;
|
||||
static unsigned int sample_rate;
|
||||
static unsigned long pixel_clk_rate;
|
||||
static struct clk *pixel_clk;
|
||||
static int hdmi_ratio;
|
||||
int mxc_hdmi_ipu_id;
|
||||
int mxc_hdmi_disp_id;
|
||||
static struct mxc_edid_cfg hdmi_core_edid_cfg;
|
||||
static int hdmi_core_init;
|
||||
static unsigned int hdmi_dma_running;
|
||||
static struct snd_pcm_substream *hdmi_audio_stream_playback;
|
||||
static unsigned int hdmi_cable_state;
|
||||
static unsigned int hdmi_blank_state;
|
||||
static unsigned int hdmi_abort_state;
|
||||
static spinlock_t hdmi_audio_lock, hdmi_blank_state_lock, hdmi_cable_state_lock;
|
||||
|
||||
unsigned int hdmi_set_cable_state(unsigned int state)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct snd_pcm_substream *substream = hdmi_audio_stream_playback;
|
||||
|
||||
spin_lock_irqsave(&hdmi_cable_state_lock, flags);
|
||||
hdmi_cable_state = state;
|
||||
spin_unlock_irqrestore(&hdmi_cable_state_lock, flags);
|
||||
|
||||
#ifndef CONFIG_MFD_MXC_HDMI_ANDROID
|
||||
if (check_hdmi_state() && substream && hdmi_abort_state) {
|
||||
hdmi_abort_state = 0;
|
||||
substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_set_cable_state);
|
||||
|
||||
unsigned int hdmi_set_blank_state(unsigned int state)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct snd_pcm_substream *substream = hdmi_audio_stream_playback;
|
||||
|
||||
spin_lock_irqsave(&hdmi_blank_state_lock, flags);
|
||||
hdmi_blank_state = state;
|
||||
spin_unlock_irqrestore(&hdmi_blank_state_lock, flags);
|
||||
|
||||
#ifndef CONFIG_MFD_MXC_HDMI_ANDROID
|
||||
if (check_hdmi_state() && substream && hdmi_abort_state) {
|
||||
hdmi_abort_state = 0;
|
||||
substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_set_blank_state);
|
||||
|
||||
static void hdmi_audio_abort_stream(struct snd_pcm_substream *substream)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
snd_pcm_stream_lock_irqsave(substream, flags);
|
||||
|
||||
#ifndef CONFIG_MFD_MXC_HDMI_ANDROID
|
||||
if (snd_pcm_running(substream)) {
|
||||
hdmi_abort_state = 1;
|
||||
substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
|
||||
}
|
||||
#else
|
||||
if (snd_pcm_running(substream))
|
||||
snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
|
||||
#endif
|
||||
|
||||
snd_pcm_stream_unlock_irqrestore(substream, flags);
|
||||
}
|
||||
|
||||
int mxc_hdmi_abort_stream(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&hdmi_audio_lock, flags);
|
||||
if (hdmi_audio_stream_playback)
|
||||
hdmi_audio_abort_stream(hdmi_audio_stream_playback);
|
||||
spin_unlock_irqrestore(&hdmi_audio_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mxc_hdmi_abort_stream);
|
||||
|
||||
int check_hdmi_state(void)
|
||||
{
|
||||
unsigned long flags1, flags2;
|
||||
unsigned int ret;
|
||||
|
||||
spin_lock_irqsave(&hdmi_cable_state_lock, flags1);
|
||||
spin_lock_irqsave(&hdmi_blank_state_lock, flags2);
|
||||
|
||||
ret = hdmi_cable_state && hdmi_blank_state;
|
||||
|
||||
spin_unlock_irqrestore(&hdmi_blank_state_lock, flags2);
|
||||
spin_unlock_irqrestore(&hdmi_cable_state_lock, flags1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(check_hdmi_state);
|
||||
|
||||
int mxc_hdmi_register_audio(struct snd_pcm_substream *substream)
|
||||
{
|
||||
unsigned long flags, flags1;
|
||||
int ret = 0;
|
||||
|
||||
snd_pcm_stream_lock_irqsave(substream, flags);
|
||||
|
||||
if (substream && check_hdmi_state()) {
|
||||
spin_lock_irqsave(&hdmi_audio_lock, flags1);
|
||||
if (hdmi_audio_stream_playback) {
|
||||
pr_err("%s unconsist hdmi auido stream!\n", __func__);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
hdmi_audio_stream_playback = substream;
|
||||
hdmi_abort_state = 0;
|
||||
spin_unlock_irqrestore(&hdmi_audio_lock, flags1);
|
||||
} else
|
||||
ret = -EINVAL;
|
||||
|
||||
snd_pcm_stream_unlock_irqrestore(substream, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mxc_hdmi_register_audio);
|
||||
|
||||
void mxc_hdmi_unregister_audio(struct snd_pcm_substream *substream)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&hdmi_audio_lock, flags);
|
||||
hdmi_audio_stream_playback = NULL;
|
||||
hdmi_abort_state = 0;
|
||||
spin_unlock_irqrestore(&hdmi_audio_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(mxc_hdmi_unregister_audio);
|
||||
|
||||
u8 hdmi_readb(unsigned int reg)
|
||||
{
|
||||
u8 value;
|
||||
|
||||
value = __raw_readb(hdmi_base + reg);
|
||||
|
||||
return value;
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_readb);
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool overflow_lo;
|
||||
static bool overflow_hi;
|
||||
|
||||
bool hdmi_check_overflow(void)
|
||||
{
|
||||
u8 val, lo, hi;
|
||||
|
||||
val = hdmi_readb(HDMI_IH_FC_STAT2);
|
||||
lo = (val & HDMI_IH_FC_STAT2_LOW_PRIORITY_OVERFLOW) != 0;
|
||||
hi = (val & HDMI_IH_FC_STAT2_HIGH_PRIORITY_OVERFLOW) != 0;
|
||||
|
||||
if ((lo != overflow_lo) || (hi != overflow_hi)) {
|
||||
pr_debug("%s LowPriority=%d HighPriority=%d <=======================\n",
|
||||
__func__, lo, hi);
|
||||
overflow_lo = lo;
|
||||
overflow_hi = hi;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
bool hdmi_check_overflow(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
EXPORT_SYMBOL(hdmi_check_overflow);
|
||||
|
||||
void hdmi_writeb(u8 value, unsigned int reg)
|
||||
{
|
||||
hdmi_check_overflow();
|
||||
__raw_writeb(value, hdmi_base + reg);
|
||||
hdmi_check_overflow();
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_writeb);
|
||||
|
||||
void hdmi_mask_writeb(u8 data, unsigned int reg, u8 shift, u8 mask)
|
||||
{
|
||||
u8 value = hdmi_readb(reg) & ~mask;
|
||||
value |= (data << shift) & mask;
|
||||
hdmi_writeb(value, reg);
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_mask_writeb);
|
||||
|
||||
unsigned int hdmi_read4(unsigned int reg)
|
||||
{
|
||||
/* read a four byte address from registers */
|
||||
return (hdmi_readb(reg + 3) << 24) |
|
||||
(hdmi_readb(reg + 2) << 16) |
|
||||
(hdmi_readb(reg + 1) << 8) |
|
||||
hdmi_readb(reg);
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_read4);
|
||||
|
||||
void hdmi_write4(unsigned int value, unsigned int reg)
|
||||
{
|
||||
/* write a four byte address to hdmi regs */
|
||||
hdmi_writeb(value & 0xff, reg);
|
||||
hdmi_writeb((value >> 8) & 0xff, reg + 1);
|
||||
hdmi_writeb((value >> 16) & 0xff, reg + 2);
|
||||
hdmi_writeb((value >> 24) & 0xff, reg + 3);
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_write4);
|
||||
|
||||
static void initialize_hdmi_ih_mutes(void)
|
||||
{
|
||||
u8 ih_mute;
|
||||
|
||||
/*
|
||||
* Boot up defaults are:
|
||||
* HDMI_IH_MUTE = 0x03 (disabled)
|
||||
* HDMI_IH_MUTE_* = 0x00 (enabled)
|
||||
*/
|
||||
|
||||
/* Disable top level interrupt bits in HDMI block */
|
||||
ih_mute = hdmi_readb(HDMI_IH_MUTE) |
|
||||
HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
|
||||
HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
|
||||
|
||||
hdmi_writeb(ih_mute, HDMI_IH_MUTE);
|
||||
|
||||
/* by default mask all interrupts */
|
||||
hdmi_writeb(0xff, HDMI_VP_MASK);
|
||||
hdmi_writeb(0xff, HDMI_FC_MASK0);
|
||||
hdmi_writeb(0xff, HDMI_FC_MASK1);
|
||||
hdmi_writeb(0xff, HDMI_FC_MASK2);
|
||||
hdmi_writeb(0xff, HDMI_PHY_MASK0);
|
||||
hdmi_writeb(0xff, HDMI_PHY_I2CM_INT_ADDR);
|
||||
hdmi_writeb(0xff, HDMI_PHY_I2CM_CTLINT_ADDR);
|
||||
hdmi_writeb(0xff, HDMI_AUD_INT);
|
||||
hdmi_writeb(0xff, HDMI_AUD_SPDIFINT);
|
||||
hdmi_writeb(0xff, HDMI_AUD_HBR_MASK);
|
||||
hdmi_writeb(0xff, HDMI_GP_MASK);
|
||||
hdmi_writeb(0xff, HDMI_A_APIINTMSK);
|
||||
hdmi_writeb(0xff, HDMI_CEC_MASK);
|
||||
hdmi_writeb(0xff, HDMI_I2CM_INT);
|
||||
hdmi_writeb(0xff, HDMI_I2CM_CTLINT);
|
||||
|
||||
/* Disable interrupts in the IH_MUTE_* registers */
|
||||
hdmi_writeb(0xff, HDMI_IH_MUTE_FC_STAT0);
|
||||
hdmi_writeb(0xff, HDMI_IH_MUTE_FC_STAT1);
|
||||
hdmi_writeb(0xff, HDMI_IH_MUTE_FC_STAT2);
|
||||
hdmi_writeb(0xff, HDMI_IH_MUTE_AS_STAT0);
|
||||
hdmi_writeb(0xff, HDMI_IH_MUTE_PHY_STAT0);
|
||||
hdmi_writeb(0xff, HDMI_IH_MUTE_I2CM_STAT0);
|
||||
hdmi_writeb(0xff, HDMI_IH_MUTE_CEC_STAT0);
|
||||
hdmi_writeb(0xff, HDMI_IH_MUTE_VP_STAT0);
|
||||
hdmi_writeb(0xff, HDMI_IH_MUTE_I2CMPHY_STAT0);
|
||||
hdmi_writeb(0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
|
||||
|
||||
/* Enable top level interrupt bits in HDMI block */
|
||||
ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
|
||||
HDMI_IH_MUTE_MUTE_ALL_INTERRUPT);
|
||||
hdmi_writeb(ih_mute, HDMI_IH_MUTE);
|
||||
}
|
||||
|
||||
static void hdmi_set_clock_regenerator_n(unsigned int value)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
if (!hdmi_dma_running) {
|
||||
hdmi_writeb(value & 0xff, HDMI_AUD_N1);
|
||||
hdmi_writeb(0, HDMI_AUD_N2);
|
||||
hdmi_writeb(0, HDMI_AUD_N3);
|
||||
}
|
||||
|
||||
hdmi_writeb(value & 0xff, HDMI_AUD_N1);
|
||||
hdmi_writeb((value >> 8) & 0xff, HDMI_AUD_N2);
|
||||
hdmi_writeb((value >> 16) & 0x0f, HDMI_AUD_N3);
|
||||
|
||||
/* nshift factor = 0 */
|
||||
val = hdmi_readb(HDMI_AUD_CTS3);
|
||||
val &= ~HDMI_AUD_CTS3_N_SHIFT_MASK;
|
||||
hdmi_writeb(val, HDMI_AUD_CTS3);
|
||||
}
|
||||
|
||||
static void hdmi_set_clock_regenerator_cts(unsigned int cts)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
if (!hdmi_dma_running) {
|
||||
hdmi_writeb(cts & 0xff, HDMI_AUD_CTS1);
|
||||
hdmi_writeb(0, HDMI_AUD_CTS2);
|
||||
hdmi_writeb(0, HDMI_AUD_CTS3);
|
||||
}
|
||||
|
||||
/* Must be set/cleared first */
|
||||
val = hdmi_readb(HDMI_AUD_CTS3);
|
||||
val &= ~HDMI_AUD_CTS3_CTS_MANUAL;
|
||||
hdmi_writeb(val, HDMI_AUD_CTS3);
|
||||
|
||||
hdmi_writeb(cts & 0xff, HDMI_AUD_CTS1);
|
||||
hdmi_writeb((cts >> 8) & 0xff, HDMI_AUD_CTS2);
|
||||
hdmi_writeb(((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
|
||||
HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
|
||||
}
|
||||
|
||||
static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
|
||||
unsigned int ratio)
|
||||
{
|
||||
unsigned int n = (128 * freq) / 1000;
|
||||
|
||||
switch (freq) {
|
||||
case 32000:
|
||||
if (pixel_clk == 25174000)
|
||||
n = (ratio == 150) ? 9152 : 4576;
|
||||
else if (pixel_clk == 27020000)
|
||||
n = (ratio == 150) ? 8192 : 4096;
|
||||
else if (pixel_clk == 74170000 || pixel_clk == 148350000)
|
||||
n = 11648;
|
||||
else if (pixel_clk == 297000000)
|
||||
n = (ratio == 150) ? 6144 : 3072;
|
||||
else
|
||||
n = 4096;
|
||||
break;
|
||||
|
||||
case 44100:
|
||||
if (pixel_clk == 25174000)
|
||||
n = 7007;
|
||||
else if (pixel_clk == 74170000)
|
||||
n = 17836;
|
||||
else if (pixel_clk == 148350000)
|
||||
n = (ratio == 150) ? 17836 : 8918;
|
||||
else if (pixel_clk == 297000000)
|
||||
n = (ratio == 150) ? 9408 : 4704;
|
||||
else
|
||||
n = 6272;
|
||||
break;
|
||||
|
||||
case 48000:
|
||||
if (pixel_clk == 25174000)
|
||||
n = (ratio == 150) ? 9152 : 6864;
|
||||
else if (pixel_clk == 27020000)
|
||||
n = (ratio == 150) ? 8192 : 6144;
|
||||
else if (pixel_clk == 74170000)
|
||||
n = 11648;
|
||||
else if (pixel_clk == 148350000)
|
||||
n = (ratio == 150) ? 11648 : 5824;
|
||||
else if (pixel_clk == 297000000)
|
||||
n = (ratio == 150) ? 10240 : 5120;
|
||||
else
|
||||
n = 6144;
|
||||
break;
|
||||
|
||||
case 88200:
|
||||
n = hdmi_compute_n(44100, pixel_clk, ratio) * 2;
|
||||
break;
|
||||
|
||||
case 96000:
|
||||
n = hdmi_compute_n(48000, pixel_clk, ratio) * 2;
|
||||
break;
|
||||
|
||||
case 176400:
|
||||
n = hdmi_compute_n(44100, pixel_clk, ratio) * 4;
|
||||
break;
|
||||
|
||||
case 192000:
|
||||
n = hdmi_compute_n(48000, pixel_clk, ratio) * 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
|
||||
unsigned int ratio)
|
||||
{
|
||||
unsigned int cts = 0;
|
||||
switch (freq) {
|
||||
case 32000:
|
||||
if (pixel_clk == 297000000) {
|
||||
cts = 222750;
|
||||
break;
|
||||
} else if (pixel_clk == 25174000) {
|
||||
cts = 28125;
|
||||
break;
|
||||
}
|
||||
case 48000:
|
||||
case 96000:
|
||||
case 192000:
|
||||
switch (pixel_clk) {
|
||||
case 25200000:
|
||||
case 27000000:
|
||||
case 54000000:
|
||||
case 74250000:
|
||||
case 148500000:
|
||||
cts = pixel_clk / 1000;
|
||||
break;
|
||||
case 297000000:
|
||||
cts = 247500;
|
||||
break;
|
||||
case 25174000:
|
||||
cts = 28125l;
|
||||
break;
|
||||
/*
|
||||
* All other TMDS clocks are not supported by
|
||||
* DWC_hdmi_tx. The TMDS clocks divided or
|
||||
* multiplied by 1,001 coefficients are not
|
||||
* supported.
|
||||
*/
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 44100:
|
||||
case 88200:
|
||||
case 176400:
|
||||
switch (pixel_clk) {
|
||||
case 25200000:
|
||||
cts = 28000;
|
||||
break;
|
||||
case 25174000:
|
||||
cts = 31250;
|
||||
break;
|
||||
case 27000000:
|
||||
cts = 30000;
|
||||
break;
|
||||
case 54000000:
|
||||
cts = 60000;
|
||||
break;
|
||||
case 74250000:
|
||||
cts = 82500;
|
||||
break;
|
||||
case 148500000:
|
||||
cts = 165000;
|
||||
break;
|
||||
case 297000000:
|
||||
cts = 247500;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (ratio == 100)
|
||||
return cts;
|
||||
else
|
||||
return (cts * ratio) / 100;
|
||||
}
|
||||
|
||||
static void hdmi_set_clk_regenerator(void)
|
||||
{
|
||||
unsigned int clk_n, clk_cts;
|
||||
|
||||
clk_n = hdmi_compute_n(sample_rate, pixel_clk_rate, hdmi_ratio);
|
||||
clk_cts = hdmi_compute_cts(sample_rate, pixel_clk_rate, hdmi_ratio);
|
||||
|
||||
if (clk_cts == 0) {
|
||||
pr_debug("%s: pixel clock not supported: %d\n",
|
||||
__func__, (int)pixel_clk_rate);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_debug("%s: samplerate=%d ratio=%d pixelclk=%d N=%d cts=%d\n",
|
||||
__func__, sample_rate, hdmi_ratio, (int)pixel_clk_rate,
|
||||
clk_n, clk_cts);
|
||||
|
||||
hdmi_set_clock_regenerator_cts(clk_cts);
|
||||
hdmi_set_clock_regenerator_n(clk_n);
|
||||
}
|
||||
|
||||
static int hdmi_core_get_of_property(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int err;
|
||||
int ipu_id, disp_id;
|
||||
|
||||
err = of_property_read_u32(np, "ipu_id", &ipu_id);
|
||||
if (err) {
|
||||
dev_dbg(&pdev->dev, "get of property ipu_id fail\n");
|
||||
return err;
|
||||
}
|
||||
err = of_property_read_u32(np, "disp_id", &disp_id);
|
||||
if (err) {
|
||||
dev_dbg(&pdev->dev, "get of property disp_id fail\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
mxc_hdmi_ipu_id = ipu_id;
|
||||
mxc_hdmi_disp_id = disp_id;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Need to run this before phy is enabled the first time to prevent
|
||||
* overflow condition in HDMI_IH_FC_STAT2 */
|
||||
void hdmi_init_clk_regenerator(void)
|
||||
{
|
||||
if (pixel_clk_rate == 0) {
|
||||
pixel_clk_rate = 74250000;
|
||||
hdmi_set_clk_regenerator();
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_init_clk_regenerator);
|
||||
|
||||
void hdmi_clk_regenerator_update_pixel_clock(u32 pixclock)
|
||||
{
|
||||
|
||||
if (!pixclock)
|
||||
return;
|
||||
/* Translate pixel clock in ps (pico seconds) to Hz */
|
||||
pixel_clk_rate = PICOS2KHZ(pixclock) * 1000UL;
|
||||
hdmi_set_clk_regenerator();
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_clk_regenerator_update_pixel_clock);
|
||||
|
||||
void hdmi_set_dma_mode(unsigned int dma_running)
|
||||
{
|
||||
hdmi_dma_running = dma_running;
|
||||
hdmi_set_clk_regenerator();
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_set_dma_mode);
|
||||
|
||||
void hdmi_set_sample_rate(unsigned int rate)
|
||||
{
|
||||
sample_rate = rate;
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_set_sample_rate);
|
||||
|
||||
void hdmi_set_edid_cfg(struct mxc_edid_cfg *cfg)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&edid_spinlock, flags);
|
||||
memcpy(&hdmi_core_edid_cfg, cfg, sizeof(struct mxc_edid_cfg));
|
||||
spin_unlock_irqrestore(&edid_spinlock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_set_edid_cfg);
|
||||
|
||||
void hdmi_get_edid_cfg(struct mxc_edid_cfg *cfg)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&edid_spinlock, flags);
|
||||
memcpy(cfg, &hdmi_core_edid_cfg, sizeof(struct mxc_edid_cfg));
|
||||
spin_unlock_irqrestore(&edid_spinlock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_get_edid_cfg);
|
||||
|
||||
void hdmi_set_registered(int registered)
|
||||
{
|
||||
hdmi_core_init = registered;
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_set_registered);
|
||||
|
||||
int hdmi_get_registered(void)
|
||||
{
|
||||
return hdmi_core_init;
|
||||
}
|
||||
EXPORT_SYMBOL(hdmi_get_registered);
|
||||
|
||||
static int mxc_hdmi_core_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mxc_hdmi_data *hdmi_data;
|
||||
struct resource *res;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
overflow_lo = false;
|
||||
overflow_hi = false;
|
||||
#endif
|
||||
|
||||
hdmi_core_init = 0;
|
||||
hdmi_dma_running = 0;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENOENT;
|
||||
|
||||
ret = hdmi_core_get_of_property(pdev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "get hdmi of property fail\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
hdmi_data = devm_kzalloc(&pdev->dev, sizeof(struct mxc_hdmi_data), GFP_KERNEL);
|
||||
if (!hdmi_data) {
|
||||
dev_err(&pdev->dev, "Couldn't allocate mxc hdmi mfd device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
hdmi_data->pdev = pdev;
|
||||
|
||||
pixel_clk = NULL;
|
||||
sample_rate = 48000;
|
||||
pixel_clk_rate = 0;
|
||||
hdmi_ratio = 100;
|
||||
|
||||
spin_lock_init(&irq_spinlock);
|
||||
spin_lock_init(&edid_spinlock);
|
||||
|
||||
|
||||
spin_lock_init(&hdmi_cable_state_lock);
|
||||
spin_lock_init(&hdmi_blank_state_lock);
|
||||
spin_lock_init(&hdmi_audio_lock);
|
||||
|
||||
spin_lock_irqsave(&hdmi_cable_state_lock, flags);
|
||||
hdmi_cable_state = 0;
|
||||
spin_unlock_irqrestore(&hdmi_cable_state_lock, flags);
|
||||
|
||||
spin_lock_irqsave(&hdmi_blank_state_lock, flags);
|
||||
hdmi_blank_state = 0;
|
||||
spin_unlock_irqrestore(&hdmi_blank_state_lock, flags);
|
||||
|
||||
spin_lock_irqsave(&hdmi_audio_lock, flags);
|
||||
hdmi_audio_stream_playback = NULL;
|
||||
hdmi_abort_state = 0;
|
||||
spin_unlock_irqrestore(&hdmi_audio_lock, flags);
|
||||
|
||||
mipi_core_clk = clk_get(&hdmi_data->pdev->dev, "mipi_core");
|
||||
if (IS_ERR(mipi_core_clk)) {
|
||||
ret = PTR_ERR(mipi_core_clk);
|
||||
dev_err(&hdmi_data->pdev->dev,
|
||||
"Unable to get mipi core clk: %d\n", ret);
|
||||
goto eclkg;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(mipi_core_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Cannot enable mipi core clock: %d\n", ret);
|
||||
goto eclke;
|
||||
}
|
||||
|
||||
isfr_clk = clk_get(&hdmi_data->pdev->dev, "hdmi_isfr");
|
||||
if (IS_ERR(isfr_clk)) {
|
||||
ret = PTR_ERR(isfr_clk);
|
||||
dev_err(&hdmi_data->pdev->dev,
|
||||
"Unable to get HDMI isfr clk: %d\n", ret);
|
||||
goto eclkg1;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(isfr_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Cannot enable HDMI clock: %d\n", ret);
|
||||
goto eclke1;
|
||||
}
|
||||
|
||||
pr_debug("%s isfr_clk:%d\n", __func__,
|
||||
(int)clk_get_rate(isfr_clk));
|
||||
|
||||
iahb_clk = clk_get(&hdmi_data->pdev->dev, "hdmi_iahb");
|
||||
if (IS_ERR(iahb_clk)) {
|
||||
ret = PTR_ERR(iahb_clk);
|
||||
dev_err(&hdmi_data->pdev->dev,
|
||||
"Unable to get HDMI iahb clk: %d\n", ret);
|
||||
goto eclkg2;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(iahb_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Cannot enable HDMI clock: %d\n", ret);
|
||||
goto eclke2;
|
||||
}
|
||||
|
||||
hdmi_data->reg_phys_base = res->start;
|
||||
if (!request_mem_region(res->start, resource_size(res),
|
||||
dev_name(&pdev->dev))) {
|
||||
dev_err(&pdev->dev, "request_mem_region failed\n");
|
||||
ret = -EBUSY;
|
||||
goto emem;
|
||||
}
|
||||
|
||||
hdmi_data->reg_base = ioremap(res->start, resource_size(res));
|
||||
if (!hdmi_data->reg_base) {
|
||||
dev_err(&pdev->dev, "ioremap failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto eirq;
|
||||
}
|
||||
hdmi_base = hdmi_data->reg_base;
|
||||
|
||||
pr_debug("\n%s hdmi hw base = 0x%08x\n\n", __func__, (int)res->start);
|
||||
|
||||
initialize_hdmi_ih_mutes();
|
||||
|
||||
/* Disable HDMI clocks until video/audio sub-drivers are initialized */
|
||||
clk_disable_unprepare(isfr_clk);
|
||||
clk_disable_unprepare(iahb_clk);
|
||||
clk_disable_unprepare(mipi_core_clk);
|
||||
|
||||
/* Replace platform data coming in with a local struct */
|
||||
platform_set_drvdata(pdev, hdmi_data);
|
||||
|
||||
return ret;
|
||||
|
||||
eirq:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
emem:
|
||||
clk_disable_unprepare(iahb_clk);
|
||||
eclke2:
|
||||
clk_put(iahb_clk);
|
||||
eclkg2:
|
||||
clk_disable_unprepare(isfr_clk);
|
||||
eclke1:
|
||||
clk_put(isfr_clk);
|
||||
eclkg1:
|
||||
clk_disable_unprepare(mipi_core_clk);
|
||||
eclke:
|
||||
clk_put(mipi_core_clk);
|
||||
eclkg:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int __exit mxc_hdmi_core_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mxc_hdmi_data *hdmi_data = platform_get_drvdata(pdev);
|
||||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
iounmap(hdmi_data->reg_base);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id imx_hdmi_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx6q-hdmi-core", },
|
||||
{ .compatible = "fsl,imx6dl-hdmi-core", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver mxc_hdmi_core_driver = {
|
||||
.driver = {
|
||||
.name = "mxc_hdmi_core",
|
||||
.of_match_table = imx_hdmi_dt_ids,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.remove = __exit_p(mxc_hdmi_core_remove),
|
||||
};
|
||||
|
||||
static int __init mxc_hdmi_core_init(void)
|
||||
{
|
||||
return platform_driver_probe(&mxc_hdmi_core_driver,
|
||||
mxc_hdmi_core_probe);
|
||||
}
|
||||
|
||||
static void __exit mxc_hdmi_core_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mxc_hdmi_core_driver);
|
||||
}
|
||||
|
||||
subsys_initcall(mxc_hdmi_core_init);
|
||||
module_exit(mxc_hdmi_core_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Core driver for Freescale i.Mx on-chip HDMI");
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -4,9 +4,18 @@ if ARCH_MXC
|
|||
|
||||
menu "MXC support drivers"
|
||||
|
||||
config MXC_IPU
|
||||
bool "Image Processing Unit Driver"
|
||||
select MXC_IPU_V3
|
||||
help
|
||||
If you plan to use the Image Processing unit, say
|
||||
Y here. IPU is needed by Framebuffer and V4L2 drivers.
|
||||
|
||||
source "drivers/mxc/mlb/Kconfig"
|
||||
source "drivers/mxc/ipu3/Kconfig"
|
||||
source "drivers/mxc/sim/Kconfig"
|
||||
source "drivers/mxc/vpu/Kconfig"
|
||||
source "drivers/mxc/hdmi-cec/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
obj-$(CONFIG_MXC_MLB) += mlb/
|
||||
obj-$(CONFIG_MXC_SIM) += sim/
|
||||
obj-$(CONFIG_MXC_VPU) += vpu/
|
||||
obj-$(CONFIG_MXC_IPU_V3) += ipu3/
|
||||
obj-$(CONFIG_MXC_HDMI_CEC) += hdmi-cec/
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
menu "MXC HDMI CEC (Consumer Electronics Control) support"
|
||||
|
||||
config MXC_HDMI_CEC
|
||||
tristate "Support for MXC HDMI CEC (Consumer Electronics Control)"
|
||||
depends on MFD_MXC_HDMI
|
||||
depends on FB_MXC_HDMI
|
||||
help
|
||||
The HDMI CEC device implement low level protocol on i.MX6x platforms.
|
||||
|
||||
endmenu
|
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_MXC_HDMI_CEC) += mxc_hdmi-cec.o
|
|
@ -0,0 +1,664 @@
|
|||
/*
|
||||
* Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file mxc_hdmi-cec.c
|
||||
*
|
||||
* @brief HDMI CEC system initialization and file operation implementation
|
||||
*
|
||||
* @ingroup HDMI
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fsl_devices.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#include <linux/console.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/mfd/mxc-hdmi-core.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
|
||||
#include <video/mxc_hdmi.h>
|
||||
|
||||
#include "mxc_hdmi-cec.h"
|
||||
|
||||
|
||||
#define MAX_MESSAGE_LEN 17
|
||||
|
||||
#define MESSAGE_TYPE_RECEIVE_SUCCESS 1
|
||||
#define MESSAGE_TYPE_NOACK 2
|
||||
#define MESSAGE_TYPE_DISCONNECTED 3
|
||||
#define MESSAGE_TYPE_CONNECTED 4
|
||||
#define MESSAGE_TYPE_SEND_SUCCESS 5
|
||||
|
||||
|
||||
struct hdmi_cec_priv {
|
||||
int receive_error;
|
||||
int send_error;
|
||||
u8 Logical_address;
|
||||
bool cec_state;
|
||||
u8 last_msg[MAX_MESSAGE_LEN];
|
||||
u8 msg_len;
|
||||
u8 latest_cec_stat;
|
||||
spinlock_t irq_lock;
|
||||
struct delayed_work hdmi_cec_work;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
struct hdmi_cec_event {
|
||||
int event_type;
|
||||
int msg_len;
|
||||
u8 msg[MAX_MESSAGE_LEN];
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static LIST_HEAD(head);
|
||||
|
||||
static int hdmi_cec_major;
|
||||
static struct class *hdmi_cec_class;
|
||||
static struct hdmi_cec_priv hdmi_cec_data;
|
||||
static u8 open_count;
|
||||
|
||||
static wait_queue_head_t hdmi_cec_queue;
|
||||
static irqreturn_t mxc_hdmi_cec_isr(int irq, void *data)
|
||||
{
|
||||
struct hdmi_cec_priv *hdmi_cec = data;
|
||||
u8 cec_stat = 0;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&hdmi_cec->irq_lock, flags);
|
||||
|
||||
hdmi_writeb(0x7f, HDMI_IH_MUTE_CEC_STAT0);
|
||||
|
||||
cec_stat = hdmi_readb(HDMI_IH_CEC_STAT0);
|
||||
hdmi_writeb(cec_stat, HDMI_IH_CEC_STAT0);
|
||||
|
||||
if ((cec_stat & (HDMI_IH_CEC_STAT0_ERROR_INIT | \
|
||||
HDMI_IH_CEC_STAT0_NACK | HDMI_IH_CEC_STAT0_EOM | \
|
||||
HDMI_IH_CEC_STAT0_DONE)) == 0) {
|
||||
spin_unlock_irqrestore(&hdmi_cec->irq_lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
pr_debug("HDMI CEC interrupt received\n");
|
||||
hdmi_cec->latest_cec_stat = cec_stat;
|
||||
|
||||
schedule_delayed_work(&(hdmi_cec->hdmi_cec_work), msecs_to_jiffies(20));
|
||||
|
||||
spin_unlock_irqrestore(&hdmi_cec->irq_lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void mxc_hdmi_cec_handle(u16 cec_stat)
|
||||
{
|
||||
u8 val = 0, i = 0;
|
||||
struct hdmi_cec_event *event = NULL;
|
||||
|
||||
/* The current transmission is successful (for initiator only). */
|
||||
if (!open_count)
|
||||
return;
|
||||
|
||||
if (cec_stat & HDMI_IH_CEC_STAT0_DONE) {
|
||||
|
||||
event = vmalloc(sizeof(struct hdmi_cec_event));
|
||||
if (NULL == event) {
|
||||
pr_err("%s: Not enough memory!\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(event, 0, sizeof(struct hdmi_cec_event));
|
||||
event->event_type = MESSAGE_TYPE_SEND_SUCCESS;
|
||||
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
list_add_tail(&event->list, &head);
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
|
||||
wake_up(&hdmi_cec_queue);
|
||||
}
|
||||
|
||||
/* EOM is detected so that the received data is ready
|
||||
* in the receiver data buffer
|
||||
*/
|
||||
if (cec_stat & HDMI_IH_CEC_STAT0_EOM) {
|
||||
|
||||
hdmi_writeb(0x02, HDMI_IH_CEC_STAT0);
|
||||
|
||||
event = vmalloc(sizeof(struct hdmi_cec_event));
|
||||
if (NULL == event) {
|
||||
pr_err("%s: Not enough memory!\n", __func__);
|
||||
return;
|
||||
}
|
||||
memset(event, 0, sizeof(struct hdmi_cec_event));
|
||||
|
||||
event->msg_len = hdmi_readb(HDMI_CEC_RX_CNT);
|
||||
if (!event->msg_len) {
|
||||
pr_err("%s: Invalid CEC message length!\n", __func__);
|
||||
return;
|
||||
}
|
||||
event->event_type = MESSAGE_TYPE_RECEIVE_SUCCESS;
|
||||
|
||||
for (i = 0; i < event->msg_len; i++)
|
||||
event->msg[i] = hdmi_readb(HDMI_CEC_RX_DATA0+i);
|
||||
hdmi_writeb(0x0, HDMI_CEC_LOCK);
|
||||
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
list_add_tail(&event->list, &head);
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
|
||||
wake_up(&hdmi_cec_queue);
|
||||
}
|
||||
|
||||
/* An error is detected on cec line (for initiator only). */
|
||||
if (cec_stat & HDMI_IH_CEC_STAT0_ERROR_INIT) {
|
||||
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
hdmi_cec_data.send_error++;
|
||||
if (hdmi_cec_data.send_error > 5) {
|
||||
pr_err("%s:Re-transmission is attempted more than 5 times!\n",
|
||||
__func__);
|
||||
hdmi_cec_data.send_error = 0;
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < hdmi_cec_data.msg_len; i++) {
|
||||
hdmi_writeb(hdmi_cec_data.last_msg[i],
|
||||
HDMI_CEC_TX_DATA0 + i);
|
||||
}
|
||||
hdmi_writeb(hdmi_cec_data.msg_len, HDMI_CEC_TX_CNT);
|
||||
|
||||
val = hdmi_readb(HDMI_CEC_CTRL);
|
||||
val |= 0x01;
|
||||
hdmi_writeb(val, HDMI_CEC_CTRL);
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
}
|
||||
|
||||
/* A frame is not acknowledged in a directly addressed message.
|
||||
* Or a frame is negatively acknowledged in
|
||||
* a broadcast message (for initiator only).
|
||||
*/
|
||||
if (cec_stat & HDMI_IH_CEC_STAT0_NACK) {
|
||||
event = vmalloc(sizeof(struct hdmi_cec_event));
|
||||
if (NULL == event) {
|
||||
pr_err("%s: Not enough memory\n", __func__);
|
||||
return;
|
||||
}
|
||||
memset(event, 0, sizeof(struct hdmi_cec_event));
|
||||
event->event_type = MESSAGE_TYPE_NOACK;
|
||||
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
list_add_tail(&event->list, &head);
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
|
||||
wake_up(&hdmi_cec_queue);
|
||||
}
|
||||
|
||||
/* An error is notified by a follower.
|
||||
* Abnormal logic data bit error (for follower).
|
||||
*/
|
||||
if (cec_stat & HDMI_IH_CEC_STAT0_ERROR_FOLL) {
|
||||
hdmi_cec_data.receive_error++;
|
||||
}
|
||||
|
||||
/* HDMI cable connected */
|
||||
if (cec_stat & 0x80) {
|
||||
event = vmalloc(sizeof(struct hdmi_cec_event));
|
||||
if (NULL == event) {
|
||||
pr_err("%s: Not enough memory\n", __func__);
|
||||
return;
|
||||
}
|
||||
memset(event, 0, sizeof(struct hdmi_cec_event));
|
||||
event->event_type = MESSAGE_TYPE_CONNECTED;
|
||||
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
list_add_tail(&event->list, &head);
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
|
||||
wake_up(&hdmi_cec_queue);
|
||||
}
|
||||
|
||||
/* HDMI cable disconnected */
|
||||
if (cec_stat & 0x100) {
|
||||
event = vmalloc(sizeof(struct hdmi_cec_event));
|
||||
if (NULL == event) {
|
||||
pr_err("%s: Not enough memory!\n", __func__);
|
||||
return;
|
||||
}
|
||||
memset(event, 0, sizeof(struct hdmi_cec_event));
|
||||
event->event_type = MESSAGE_TYPE_DISCONNECTED;
|
||||
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
list_add_tail(&event->list, &head);
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
|
||||
wake_up(&hdmi_cec_queue);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(mxc_hdmi_cec_handle);
|
||||
|
||||
static void mxc_hdmi_cec_worker(struct work_struct *work)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
mxc_hdmi_cec_handle(hdmi_cec_data.latest_cec_stat);
|
||||
val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL |
|
||||
HDMI_IH_CEC_STAT0_ARB_LOST;
|
||||
hdmi_writeb(val, HDMI_IH_MUTE_CEC_STAT0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief open function for vpu file operation
|
||||
*
|
||||
* @return 0 on success or negative error code on error
|
||||
*/
|
||||
static int hdmi_cec_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
if (open_count) {
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
open_count = 1;
|
||||
filp->private_data = (void *)(&hdmi_cec_data);
|
||||
hdmi_cec_data.Logical_address = 15;
|
||||
hdmi_cec_data.cec_state = false;
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t hdmi_cec_read(struct file *file, char __user *buf, size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct hdmi_cec_event *event = NULL;
|
||||
|
||||
pr_debug("function : %s\n", __func__);
|
||||
if (!open_count)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
if (false == hdmi_cec_data.cec_state) {
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
return -EACCES;
|
||||
}
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
|
||||
/* delete from list */
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
if (list_empty(&head)) {
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
return -EACCES;
|
||||
}
|
||||
event = list_first_entry(&head, struct hdmi_cec_event, list);
|
||||
list_del(&event->list);
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
|
||||
if (copy_to_user(buf, event,
|
||||
sizeof(struct hdmi_cec_event) - sizeof(struct list_head))) {
|
||||
vfree(event);
|
||||
return -EFAULT;
|
||||
}
|
||||
vfree(event);
|
||||
|
||||
return sizeof(struct hdmi_cec_event);
|
||||
}
|
||||
|
||||
static ssize_t hdmi_cec_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
int ret = 0 , i = 0;
|
||||
u8 msg[MAX_MESSAGE_LEN];
|
||||
u8 msg_len = 0, val = 0;
|
||||
|
||||
pr_debug("function : %s\n", __func__);
|
||||
if (!open_count)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
if (false == hdmi_cec_data.cec_state) {
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
return -EACCES;
|
||||
}
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
|
||||
if (count > MAX_MESSAGE_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
hdmi_cec_data.send_error = 0;
|
||||
memset(&msg, 0, MAX_MESSAGE_LEN);
|
||||
ret = copy_from_user(&msg, buf, count);
|
||||
if (ret) {
|
||||
ret = -EACCES;
|
||||
goto end;
|
||||
}
|
||||
|
||||
msg_len = count;
|
||||
hdmi_writeb(msg_len, HDMI_CEC_TX_CNT);
|
||||
for (i = 0; i < msg_len; i++) {
|
||||
hdmi_writeb(msg[i], HDMI_CEC_TX_DATA0+i);
|
||||
}
|
||||
|
||||
val = hdmi_readb(HDMI_CEC_CTRL);
|
||||
val |= 0x01;
|
||||
hdmi_writeb(val, HDMI_CEC_CTRL);
|
||||
memcpy(hdmi_cec_data.last_msg, msg, msg_len);
|
||||
hdmi_cec_data.msg_len = msg_len;
|
||||
|
||||
i = 0;
|
||||
val = hdmi_readb(HDMI_CEC_CTRL);
|
||||
while ((val & 0x01) == 0x1) {
|
||||
msleep(50);
|
||||
i++;
|
||||
if (i > 3) {
|
||||
ret = -EIO;
|
||||
goto end;
|
||||
}
|
||||
val = hdmi_readb(HDMI_CEC_CTRL);
|
||||
}
|
||||
|
||||
end:
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief IO ctrl function for vpu file operation
|
||||
* @param cmd IO ctrl command
|
||||
* @return 0 on success or negative error code on error
|
||||
*/
|
||||
static long hdmi_cec_ioctl(struct file *filp, u_int cmd,
|
||||
u_long arg)
|
||||
{
|
||||
int ret = 0, status = 0;
|
||||
u8 val = 0, msg = 0;
|
||||
struct mxc_edid_cfg hdmi_edid_cfg;
|
||||
|
||||
pr_debug("function : %s\n", __func__);
|
||||
if (!open_count)
|
||||
return -ENODEV;
|
||||
|
||||
switch (cmd) {
|
||||
case HDMICEC_IOC_SETLOGICALADDRESS:
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
if (false == hdmi_cec_data.cec_state) {
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
hdmi_cec_data.Logical_address = (u8)arg;
|
||||
|
||||
if (hdmi_cec_data.Logical_address <= 7) {
|
||||
val = 1 << hdmi_cec_data.Logical_address;
|
||||
hdmi_writeb(val, HDMI_CEC_ADDR_L);
|
||||
hdmi_writeb(0, HDMI_CEC_ADDR_H);
|
||||
} else if (hdmi_cec_data.Logical_address > 7 &&
|
||||
hdmi_cec_data.Logical_address <= 15) {
|
||||
val = 1 << (hdmi_cec_data.Logical_address - 8);
|
||||
hdmi_writeb(val, HDMI_CEC_ADDR_H);
|
||||
hdmi_writeb(0, HDMI_CEC_ADDR_L);
|
||||
} else {
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
/* Send Polling message with same source
|
||||
* and destination address
|
||||
*/
|
||||
if (0 == ret && 15 != hdmi_cec_data.Logical_address) {
|
||||
msg = (hdmi_cec_data.Logical_address << 4) |
|
||||
hdmi_cec_data.Logical_address;
|
||||
hdmi_writeb(1, HDMI_CEC_TX_CNT);
|
||||
hdmi_writeb(msg, HDMI_CEC_TX_DATA0);
|
||||
|
||||
val = hdmi_readb(HDMI_CEC_CTRL);
|
||||
val |= 0x01;
|
||||
hdmi_writeb(val, HDMI_CEC_CTRL);
|
||||
}
|
||||
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
break;
|
||||
|
||||
case HDMICEC_IOC_STARTDEVICE:
|
||||
val = hdmi_readb(HDMI_MC_CLKDIS);
|
||||
val &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
|
||||
hdmi_writeb(val, HDMI_MC_CLKDIS);
|
||||
|
||||
hdmi_writeb(0x02, HDMI_CEC_CTRL);
|
||||
|
||||
val = HDMI_IH_CEC_STAT0_ERROR_INIT | HDMI_IH_CEC_STAT0_NACK |
|
||||
HDMI_IH_CEC_STAT0_EOM | HDMI_IH_CEC_STAT0_DONE;
|
||||
hdmi_writeb(val, HDMI_CEC_POLARITY);
|
||||
|
||||
val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL |
|
||||
HDMI_IH_CEC_STAT0_ARB_LOST;
|
||||
hdmi_writeb(val, HDMI_CEC_MASK);
|
||||
hdmi_writeb(val, HDMI_IH_MUTE_CEC_STAT0);
|
||||
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
hdmi_cec_data.cec_state = true;
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
break;
|
||||
|
||||
case HDMICEC_IOC_STOPDEVICE:
|
||||
hdmi_writeb(0x10, HDMI_CEC_CTRL);
|
||||
|
||||
val = HDMI_IH_CEC_STAT0_WAKEUP | HDMI_IH_CEC_STAT0_ERROR_FOLL |
|
||||
HDMI_IH_CEC_STAT0_ERROR_INIT | HDMI_IH_CEC_STAT0_ARB_LOST |
|
||||
HDMI_IH_CEC_STAT0_NACK | HDMI_IH_CEC_STAT0_EOM |
|
||||
HDMI_IH_CEC_STAT0_DONE;
|
||||
hdmi_writeb(val, HDMI_CEC_MASK);
|
||||
hdmi_writeb(val, HDMI_IH_MUTE_CEC_STAT0);
|
||||
|
||||
hdmi_writeb(0x0, HDMI_CEC_POLARITY);
|
||||
|
||||
val = hdmi_readb(HDMI_MC_CLKDIS);
|
||||
val |= HDMI_MC_CLKDIS_CECCLK_DISABLE;
|
||||
hdmi_writeb(val, HDMI_MC_CLKDIS);
|
||||
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
hdmi_cec_data.cec_state = false;
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
break;
|
||||
|
||||
case HDMICEC_IOC_GETPHYADDRESS:
|
||||
hdmi_get_edid_cfg(&hdmi_edid_cfg);
|
||||
status = copy_to_user((void __user *)arg,
|
||||
&hdmi_edid_cfg.physical_address,
|
||||
4*sizeof(u8));
|
||||
if (status)
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Release function for vpu file operation
|
||||
* @return 0 on success or negative error code on error
|
||||
*/
|
||||
static int hdmi_cec_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
mutex_lock(&hdmi_cec_data.lock);
|
||||
|
||||
if (open_count) {
|
||||
open_count = 0;
|
||||
hdmi_cec_data.cec_state = false;
|
||||
hdmi_cec_data.Logical_address = 15;
|
||||
}
|
||||
|
||||
mutex_unlock(&hdmi_cec_data.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int hdmi_cec_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
|
||||
pr_debug("function : %s\n", __func__);
|
||||
|
||||
if (!open_count)
|
||||
return -ENODEV;
|
||||
|
||||
if (false == hdmi_cec_data.cec_state)
|
||||
return -EACCES;
|
||||
|
||||
poll_wait(file, &hdmi_cec_queue, wait);
|
||||
|
||||
if (!list_empty(&head))
|
||||
mask |= (POLLIN | POLLRDNORM);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
const struct file_operations hdmi_cec_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = hdmi_cec_read,
|
||||
.write = hdmi_cec_write,
|
||||
.open = hdmi_cec_open,
|
||||
.unlocked_ioctl = hdmi_cec_ioctl,
|
||||
.release = hdmi_cec_release,
|
||||
.poll = hdmi_cec_poll,
|
||||
};
|
||||
|
||||
static int hdmi_cec_dev_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err = 0;
|
||||
struct device *temp_class;
|
||||
struct resource *res;
|
||||
struct pinctrl *pinctrl;
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
|
||||
hdmi_cec_major = register_chrdev(hdmi_cec_major,
|
||||
"mxc_hdmi_cec", &hdmi_cec_fops);
|
||||
if (hdmi_cec_major < 0) {
|
||||
dev_err(&pdev->dev, "hdmi_cec: unable to get a major for HDMI CEC\n");
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (unlikely(res == NULL)) {
|
||||
dev_err(&pdev->dev, "hdmi_cec:No HDMI irq line provided\n");
|
||||
goto err_out_chrdev;
|
||||
}
|
||||
|
||||
spin_lock_init(&hdmi_cec_data.irq_lock);
|
||||
|
||||
err = devm_request_irq(&pdev->dev, irq, mxc_hdmi_cec_isr, IRQF_SHARED,
|
||||
dev_name(&pdev->dev), &hdmi_cec_data);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "hdmi_cec:Unable to request irq: %d\n", err);
|
||||
goto err_out_chrdev;
|
||||
}
|
||||
|
||||
hdmi_cec_class = class_create(THIS_MODULE, "mxc_hdmi_cec");
|
||||
if (IS_ERR(hdmi_cec_class)) {
|
||||
err = PTR_ERR(hdmi_cec_class);
|
||||
goto err_out_chrdev;
|
||||
}
|
||||
|
||||
temp_class = device_create(hdmi_cec_class, NULL,
|
||||
MKDEV(hdmi_cec_major, 0), NULL, "mxc_hdmi_cec");
|
||||
if (IS_ERR(temp_class)) {
|
||||
err = PTR_ERR(temp_class);
|
||||
goto err_out_class;
|
||||
}
|
||||
|
||||
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
||||
if (IS_ERR(pinctrl)) {
|
||||
dev_err(&pdev->dev, "can't get/select CEC pinctrl\n");
|
||||
goto err_out_class;
|
||||
}
|
||||
|
||||
init_waitqueue_head(&hdmi_cec_queue);
|
||||
|
||||
INIT_LIST_HEAD(&head);
|
||||
|
||||
mutex_init(&hdmi_cec_data.lock);
|
||||
|
||||
hdmi_cec_data.Logical_address = 15;
|
||||
|
||||
platform_set_drvdata(pdev, &hdmi_cec_data);
|
||||
|
||||
INIT_DELAYED_WORK(&hdmi_cec_data.hdmi_cec_work, mxc_hdmi_cec_worker);
|
||||
|
||||
dev_info(&pdev->dev, "HDMI CEC initialized\n");
|
||||
goto out;
|
||||
|
||||
err_out_class:
|
||||
device_destroy(hdmi_cec_class, MKDEV(hdmi_cec_major, 0));
|
||||
class_destroy(hdmi_cec_class);
|
||||
err_out_chrdev:
|
||||
unregister_chrdev(hdmi_cec_major, "mxc_hdmi_cec");
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int hdmi_cec_dev_remove(struct platform_device *pdev)
|
||||
{
|
||||
if (hdmi_cec_major > 0) {
|
||||
device_destroy(hdmi_cec_class, MKDEV(hdmi_cec_major, 0));
|
||||
class_destroy(hdmi_cec_class);
|
||||
unregister_chrdev(hdmi_cec_major, "mxc_hdmi_cec");
|
||||
hdmi_cec_major = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id imx_hdmi_cec_match[] = {
|
||||
{ .compatible = "fsl,imx6q-hdmi-cec", },
|
||||
{ .compatible = "fsl,imx6dl-hdmi-cec", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver mxc_hdmi_cec_driver = {
|
||||
.probe = hdmi_cec_dev_probe,
|
||||
.remove = hdmi_cec_dev_remove,
|
||||
.driver = {
|
||||
.name = "mxc_hdmi_cec",
|
||||
.of_match_table = imx_hdmi_cec_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(mxc_hdmi_cec_driver);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("Linux HDMI CEC driver for Freescale i.MX/MXC");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:mxc_hdmi_cec");
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
#ifndef _HDMICEC_H_
|
||||
#define _HDMICEC_H_
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
/*
|
||||
* Ioctl definitions
|
||||
*/
|
||||
|
||||
/* Use 'k' as magic number */
|
||||
#define HDMICEC_IOC_MAGIC 'H'
|
||||
/*
|
||||
* S means "Set" through a ptr,
|
||||
* T means "Tell" directly with the argument value
|
||||
* G means "Get": reply by setting through a pointer
|
||||
* Q means "Query": response is on the return value
|
||||
* X means "eXchange": G and S atomically
|
||||
* H means "sHift": T and Q atomically
|
||||
*/
|
||||
#define HDMICEC_IOC_SETLOGICALADDRESS \
|
||||
_IOW(HDMICEC_IOC_MAGIC, 1, unsigned char)
|
||||
#define HDMICEC_IOC_STARTDEVICE _IO(HDMICEC_IOC_MAGIC, 2)
|
||||
#define HDMICEC_IOC_STOPDEVICE _IO(HDMICEC_IOC_MAGIC, 3)
|
||||
#define HDMICEC_IOC_GETPHYADDRESS \
|
||||
_IOR(HDMICEC_IOC_MAGIC, 4, unsigned char[4])
|
||||
|
||||
#endif /* !_HDMICEC_H_ */
|
|
@ -0,0 +1,21 @@
|
|||
config MXC_IPU_V3
|
||||
bool
|
||||
|
||||
config MXC_IPU_V3_PRG
|
||||
tristate "i.MX IPUv3 prefetch gasket engine"
|
||||
depends on MXC_IPU_V3 && MXC_IPU_V3_PRE
|
||||
help
|
||||
This enables support for the IPUv3 prefetch gasket engine to
|
||||
support double buffer handshake control bewteen IPUv3 and
|
||||
prefetch engine(PRE), snoop the AXI interface for display
|
||||
refresh requests to memory and modify the request address to
|
||||
fetch the double buffered row of blocks in OCRAM.
|
||||
|
||||
config MXC_IPU_V3_PRE
|
||||
tristate "i.MX IPUv3 prefetch engine"
|
||||
depends on MXC_IPU_V3
|
||||
select MXC_IPU_V3_PRG
|
||||
help
|
||||
This enables support for the IPUv3 prefetch engine to improve
|
||||
the system memory performance. The engine has the capability
|
||||
to resolve framebuffers in tile pixel format to linear.
|
|
@ -0,0 +1,7 @@
|
|||
obj-$(CONFIG_MXC_IPU_V3) = mxc_ipu.o
|
||||
|
||||
obj-$(CONFIG_MXC_IPU_V3_PRG) += prg.o
|
||||
obj-$(CONFIG_MXC_IPU_V3_PRE) += pre.o
|
||||
|
||||
mxc_ipu-objs := ipu_common.o ipu_ic.o ipu_disp.o ipu_capture.o ipu_device.o \
|
||||
ipu_calc_stripes_sizes.o vdoa.o ipu_pixel_clk.o
|
|
@ -0,0 +1,495 @@
|
|||
/*
|
||||
* Copyright 2009-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* @file ipu_calc_stripes_sizes.c
|
||||
*
|
||||
* @brief IPU IC functions
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
|
||||
#include <linux/ipu-v3.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/math64.h>
|
||||
|
||||
#define BPP_32 0
|
||||
#define BPP_16 3
|
||||
#define BPP_8 5
|
||||
#define BPP_24 1
|
||||
#define BPP_12 4
|
||||
#define BPP_18 2
|
||||
|
||||
static u32 truncate(u32 up, /* 0: down; else: up */
|
||||
u64 a, /* must be non-negative */
|
||||
u32 b)
|
||||
{
|
||||
u32 d;
|
||||
u64 div;
|
||||
div = div_u64(a, b);
|
||||
d = b * (div >> 32);
|
||||
if (up && (a > (((u64)d) << 32)))
|
||||
return d+b;
|
||||
else
|
||||
return d;
|
||||
}
|
||||
|
||||
static unsigned int f_calc(unsigned int pfs, unsigned int bpp, unsigned int *write)
|
||||
{/* return input_f */
|
||||
unsigned int f_calculated = 0;
|
||||
switch (pfs) {
|
||||
case IPU_PIX_FMT_YVU422P:
|
||||
case IPU_PIX_FMT_YUV422P:
|
||||
case IPU_PIX_FMT_YUV420P2:
|
||||
case IPU_PIX_FMT_YUV420P:
|
||||
case IPU_PIX_FMT_YVU420P:
|
||||
case IPU_PIX_FMT_YUV444P:
|
||||
f_calculated = 16;
|
||||
break;
|
||||
|
||||
case IPU_PIX_FMT_RGB565:
|
||||
case IPU_PIX_FMT_YUYV:
|
||||
case IPU_PIX_FMT_UYVY:
|
||||
f_calculated = 8;
|
||||
break;
|
||||
|
||||
case IPU_PIX_FMT_NV12:
|
||||
f_calculated = 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
f_calculated = 0;
|
||||
break;
|
||||
|
||||
}
|
||||
if (!f_calculated) {
|
||||
switch (bpp) {
|
||||
case BPP_32:
|
||||
f_calculated = 2;
|
||||
break;
|
||||
|
||||
case BPP_16:
|
||||
f_calculated = 4;
|
||||
break;
|
||||
|
||||
case BPP_8:
|
||||
case BPP_24:
|
||||
f_calculated = 8;
|
||||
break;
|
||||
|
||||
case BPP_12:
|
||||
f_calculated = 16;
|
||||
break;
|
||||
|
||||
case BPP_18:
|
||||
f_calculated = 32;
|
||||
break;
|
||||
|
||||
default:
|
||||
f_calculated = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return f_calculated;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int m_calc(unsigned int pfs)
|
||||
{
|
||||
unsigned int m_calculated = 0;
|
||||
switch (pfs) {
|
||||
case IPU_PIX_FMT_YUV420P2:
|
||||
case IPU_PIX_FMT_YUV420P:
|
||||
case IPU_PIX_FMT_YVU422P:
|
||||
case IPU_PIX_FMT_YUV422P:
|
||||
case IPU_PIX_FMT_YVU420P:
|
||||
case IPU_PIX_FMT_YUV444P:
|
||||
m_calculated = 16;
|
||||
break;
|
||||
|
||||
case IPU_PIX_FMT_NV12:
|
||||
case IPU_PIX_FMT_YUYV:
|
||||
case IPU_PIX_FMT_UYVY:
|
||||
m_calculated = 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
m_calculated = 8;
|
||||
break;
|
||||
|
||||
}
|
||||
return m_calculated;
|
||||
}
|
||||
|
||||
static int calc_split_resize_coeffs(unsigned int inSize, unsigned int outSize,
|
||||
unsigned int *resizeCoeff,
|
||||
unsigned int *downsizeCoeff)
|
||||
{
|
||||
uint32_t tempSize;
|
||||
uint32_t tempDownsize;
|
||||
|
||||
if (inSize > 4096) {
|
||||
pr_debug("IC input size(%d) cannot exceed 4096\n",
|
||||
inSize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (outSize > 1024) {
|
||||
pr_debug("IC output size(%d) cannot exceed 1024\n",
|
||||
outSize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((outSize << 3) < inSize) {
|
||||
pr_debug("IC cannot downsize more than 8:1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Compute downsizing coefficient */
|
||||
/* Output of downsizing unit cannot be more than 1024 */
|
||||
tempDownsize = 0;
|
||||
tempSize = inSize;
|
||||
while (((tempSize > 1024) || (tempSize >= outSize * 2)) &&
|
||||
(tempDownsize < 2)) {
|
||||
tempSize >>= 1;
|
||||
tempDownsize++;
|
||||
}
|
||||
*downsizeCoeff = tempDownsize;
|
||||
|
||||
/* compute resizing coefficient using the following equation:
|
||||
resizeCoeff = M*(SI -1)/(SO - 1)
|
||||
where M = 2^13, SI - input size, SO - output size */
|
||||
*resizeCoeff = (8192L * (tempSize - 1)) / (outSize - 1);
|
||||
if (*resizeCoeff >= 16384L) {
|
||||
pr_debug("Overflow on IC resize coefficient.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pr_debug("resizing from %u -> %u pixels, "
|
||||
"downsize=%u, resize=%u.%lu (reg=%u)\n", inSize, outSize,
|
||||
*downsizeCoeff, (*resizeCoeff >= 8192L) ? 1 : 0,
|
||||
((*resizeCoeff & 0x1FFF) * 10000L) / 8192L, *resizeCoeff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Stripe parameters calculator */
|
||||
/**************************************************************************
|
||||
Notes:
|
||||
MSW = the maximal width allowed for a stripe
|
||||
i.MX31: 720, i.MX35: 800, i.MX37/51/53: 1024
|
||||
cirr = the maximal inverse resizing ratio for which overlap in the input
|
||||
is requested; typically cirr~2
|
||||
flags
|
||||
bit 0 - equal_stripes
|
||||
0 each stripe is allowed to have independent parameters
|
||||
for maximal image quality
|
||||
1 the stripes are requested to have identical parameters
|
||||
(except the base address), for maximal performance
|
||||
bit 1 - vertical/horizontal
|
||||
0 horizontal
|
||||
1 vertical
|
||||
|
||||
If performance is the top priority (above image quality)
|
||||
Avoid overlap, by setting CIRR = 0
|
||||
This will also force effectively identical_stripes = 1
|
||||
Choose IF & OF that corresponds to the same IOX/SX for both stripes
|
||||
Choose IFW & OFW such that
|
||||
IFW/IM, IFW/IF, OFW/OM, OFW/OF are even integers
|
||||
The function returns an error status:
|
||||
0: no error
|
||||
1: invalid input parameters -> aborted without result
|
||||
Valid parameters should satisfy the following conditions
|
||||
IFW <= OFW, otherwise downsizing is required
|
||||
- which is not supported yet
|
||||
4 <= IFW,OFW, so some interpolation may be needed even without overlap
|
||||
IM, OM, IF, OF should not vanish
|
||||
2*IF <= IFW
|
||||
so the frame can be split to two equal stripes, even without overlap
|
||||
2*(OF+IF/irr_opt) <= OFW
|
||||
so a valid positive INW exists even for equal stripes
|
||||
OF <= MSW, otherwise, the left stripe cannot be sufficiently large
|
||||
MSW < OFW, so splitting to stripes is required
|
||||
OFW <= 2*MSW, so two stripes are sufficient
|
||||
(this also implies that 2<=MSW)
|
||||
2: OF is not a multiple of OM - not fully-supported yet
|
||||
Output is produced but OW is not guaranited to be a multiple of OM
|
||||
4: OFW reduced to be a multiple of OM
|
||||
8: CIRR > 1: truncated to 1
|
||||
Overlap is not supported (and not needed) y for upsizing)
|
||||
**************************************************************************/
|
||||
int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
|
||||
/* input frame width;>1 */
|
||||
unsigned int output_frame_width, /* output frame width; >1 */
|
||||
const unsigned int maximal_stripe_width,
|
||||
/* the maximal width allowed for a stripe */
|
||||
const unsigned long long cirr, /* see above */
|
||||
const unsigned int flags, /* see above */
|
||||
u32 input_pixelformat,/* pixel format after of read channel*/
|
||||
u32 output_pixelformat,/* pixel format after of write channel*/
|
||||
struct stripe_param *left,
|
||||
struct stripe_param *right)
|
||||
{
|
||||
const unsigned int irr_frac_bits = 13;
|
||||
const unsigned long irr_steps = 1 << irr_frac_bits;
|
||||
const u64 dirr = ((u64)1) << (32 - 2);
|
||||
/* The maximum relative difference allowed between the irrs */
|
||||
const u64 cr = ((u64)4) << 32;
|
||||
/* The importance ratio between the two terms in the cost function below */
|
||||
|
||||
unsigned int status;
|
||||
unsigned int temp;
|
||||
unsigned int onw_min;
|
||||
unsigned int inw = 0, onw = 0, inw_best = 0;
|
||||
/* number of pixels in the left stripe NOT hidden by the right stripe */
|
||||
u64 irr_opt; /* the optimal inverse resizing ratio */
|
||||
u64 rr_opt; /* the optimal resizing ratio = 1/irr_opt*/
|
||||
u64 dinw; /* the misalignment between the stripes */
|
||||
/* (measured in units of input columns) */
|
||||
u64 difwl, difwr = 0;
|
||||
/* The number of input columns not reflected in the output */
|
||||
/* the resizing ratio used for the right stripe is */
|
||||
/* left->irr and right->irr respectively */
|
||||
u64 cost, cost_min;
|
||||
u64 div; /* result of division */
|
||||
bool equal_stripes = (flags & 0x1) != 0;
|
||||
bool vertical = (flags & 0x2) != 0;
|
||||
|
||||
unsigned int input_m, input_f, output_m, output_f; /* parameters for upsizing by stripes */
|
||||
unsigned int resize_coeff;
|
||||
unsigned int downsize_coeff;
|
||||
|
||||
status = 0;
|
||||
|
||||
if (vertical) {
|
||||
input_f = 2;
|
||||
input_m = 8;
|
||||
output_f = 8;
|
||||
output_m = 2;
|
||||
} else {
|
||||
input_f = f_calc(input_pixelformat, 0, NULL);
|
||||
input_m = m_calc(input_pixelformat);
|
||||
output_f = input_m;
|
||||
output_m = m_calc(output_pixelformat);
|
||||
}
|
||||
if ((input_frame_width < 4) || (output_frame_width < 4))
|
||||
return 1;
|
||||
|
||||
irr_opt = div_u64((((u64)(input_frame_width - 1)) << 32),
|
||||
(output_frame_width - 1));
|
||||
rr_opt = div_u64((((u64)(output_frame_width - 1)) << 32),
|
||||
(input_frame_width - 1));
|
||||
|
||||
if ((input_m == 0) || (output_m == 0) || (input_f == 0) || (output_f == 0)
|
||||
|| (input_frame_width < (2 * input_f))
|
||||
|| ((((u64)output_frame_width) << 32) <
|
||||
(2 * ((((u64)output_f) << 32) + (input_f * rr_opt))))
|
||||
|| (maximal_stripe_width < output_f)
|
||||
|| ((output_frame_width <= maximal_stripe_width)
|
||||
&& (equal_stripes == 0))
|
||||
|| ((2 * maximal_stripe_width) < output_frame_width))
|
||||
return 1;
|
||||
|
||||
if (output_f % output_m)
|
||||
status += 2;
|
||||
|
||||
temp = truncate(0, (((u64)output_frame_width) << 32), output_m);
|
||||
if (temp < output_frame_width) {
|
||||
output_frame_width = temp;
|
||||
status += 4;
|
||||
}
|
||||
|
||||
pr_debug("---------------->\n"
|
||||
"if = %d\n"
|
||||
"im = %d\n"
|
||||
"of = %d\n"
|
||||
"om = %d\n"
|
||||
"irr_opt = %llu\n"
|
||||
"rr_opt = %llu\n"
|
||||
"cirr = %llu\n"
|
||||
"pixel in = %08x\n"
|
||||
"pixel out = %08x\n"
|
||||
"ifw = %d\n"
|
||||
"ofwidth = %d\n",
|
||||
input_f,
|
||||
input_m,
|
||||
output_f,
|
||||
output_m,
|
||||
irr_opt,
|
||||
rr_opt,
|
||||
cirr,
|
||||
input_pixelformat,
|
||||
output_pixelformat,
|
||||
input_frame_width,
|
||||
output_frame_width
|
||||
);
|
||||
|
||||
if (equal_stripes) {
|
||||
if ((irr_opt > cirr) /* overlap in the input is not requested */
|
||||
&& ((input_frame_width % (input_m << 1)) == 0)
|
||||
&& ((input_frame_width % (input_f << 1)) == 0)
|
||||
&& ((output_frame_width % (output_m << 1)) == 0)
|
||||
&& ((output_frame_width % (output_f << 1)) == 0)) {
|
||||
/* without overlap */
|
||||
left->input_width = right->input_width = right->input_column =
|
||||
input_frame_width >> 1;
|
||||
left->output_width = right->output_width = right->output_column =
|
||||
output_frame_width >> 1;
|
||||
left->input_column = 0;
|
||||
left->output_column = 0;
|
||||
div = div_u64(((((u64)irr_steps) << 32) *
|
||||
(right->input_width - 1)), (right->output_width - 1));
|
||||
left->irr = right->irr = truncate(0, div, 1);
|
||||
} else { /* with overlap */
|
||||
onw = truncate(0, (((u64)output_frame_width - 1) << 32) >> 1,
|
||||
output_f);
|
||||
inw = truncate(0, onw * irr_opt, input_f);
|
||||
/* this is the maximal inw which allows the same resizing ratio */
|
||||
/* in both stripes */
|
||||
onw = truncate(1, (inw * rr_opt), output_f);
|
||||
div = div_u64((((u64)(irr_steps * inw)) <<
|
||||
32), onw);
|
||||
left->irr = right->irr = truncate(0, div, 1);
|
||||
left->output_width = right->output_width =
|
||||
output_frame_width - onw;
|
||||
/* These are valid assignments for output_width, */
|
||||
/* assuming output_f is a multiple of output_m */
|
||||
div = (((u64)(left->output_width-1) * (left->irr)) << 32);
|
||||
div = (((u64)1) << 32) + div_u64(div, irr_steps);
|
||||
|
||||
left->input_width = right->input_width = truncate(1, div, input_m);
|
||||
|
||||
div = div_u64((((u64)((right->output_width - 1) * right->irr)) <<
|
||||
32), irr_steps);
|
||||
difwr = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
|
||||
div = div_u64((difwr + (((u64)input_f) << 32)), 2);
|
||||
left->input_column = truncate(0, div, input_f);
|
||||
|
||||
|
||||
/* This splits the truncated input columns evenly */
|
||||
/* between the left and right margins */
|
||||
right->input_column = left->input_column + inw;
|
||||
left->output_column = 0;
|
||||
right->output_column = onw;
|
||||
}
|
||||
if (left->input_width > left->output_width) {
|
||||
if (calc_split_resize_coeffs(left->input_width,
|
||||
left->output_width,
|
||||
&resize_coeff,
|
||||
&downsize_coeff) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (downsize_coeff > 0) {
|
||||
left->irr = right->irr =
|
||||
(downsize_coeff << 14) | resize_coeff;
|
||||
}
|
||||
}
|
||||
pr_debug("inw %d, onw %d, ilw %d, ilc %d, olw %d,"
|
||||
" irw %d, irc %d, orw %d, orc %d, "
|
||||
"difwr %llu, lirr %u\n",
|
||||
inw, onw, left->input_width,
|
||||
left->input_column, left->output_width,
|
||||
right->input_width, right->input_column,
|
||||
right->output_width,
|
||||
right->output_column, difwr, left->irr);
|
||||
} else { /* independent stripes */
|
||||
onw_min = output_frame_width - maximal_stripe_width;
|
||||
/* onw is a multiple of output_f, in the range */
|
||||
/* [max(output_f,output_frame_width-maximal_stripe_width),*/
|
||||
/*min(output_frame_width-2,maximal_stripe_width)] */
|
||||
/* definitely beyond the cost of any valid setting */
|
||||
cost_min = (((u64)input_frame_width) << 32) + cr;
|
||||
onw = truncate(0, ((u64)maximal_stripe_width), output_f);
|
||||
if (output_frame_width - onw == 1)
|
||||
onw -= output_f; /* => onw and output_frame_width-1-onw are positive */
|
||||
inw = truncate(0, onw * irr_opt, input_f);
|
||||
/* this is the maximal inw which allows the same resizing ratio */
|
||||
/* in both stripes */
|
||||
onw = truncate(1, inw * rr_opt, output_f);
|
||||
do {
|
||||
div = div_u64((((u64)(irr_steps * inw)) << 32), onw);
|
||||
left->irr = truncate(0, div, 1);
|
||||
div = div_u64((((u64)(onw * left->irr)) << 32),
|
||||
irr_steps);
|
||||
dinw = (((u64)inw) << 32) - div;
|
||||
|
||||
div = div_u64((((u64)((output_frame_width - 1 - onw) * left->irr)) <<
|
||||
32), irr_steps);
|
||||
|
||||
difwl = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
|
||||
|
||||
cost = difwl + (((u64)(cr * dinw)) >> 32);
|
||||
|
||||
if (cost < cost_min) {
|
||||
inw_best = inw;
|
||||
cost_min = cost;
|
||||
}
|
||||
|
||||
inw -= input_f;
|
||||
onw = truncate(1, inw * rr_opt, output_f);
|
||||
/* This is the minimal onw which allows the same resizing ratio */
|
||||
/* in both stripes */
|
||||
} while (onw >= onw_min);
|
||||
|
||||
inw = inw_best;
|
||||
onw = truncate(1, inw * rr_opt, output_f);
|
||||
div = div_u64((((u64)(irr_steps * inw)) << 32), onw);
|
||||
left->irr = truncate(0, div, 1);
|
||||
|
||||
left->output_width = onw;
|
||||
right->output_width = output_frame_width - onw;
|
||||
/* These are valid assignments for output_width, */
|
||||
/* assuming output_f is a multiple of output_m */
|
||||
left->input_width = truncate(1, ((u64)(inw + 1)) << 32, input_m);
|
||||
right->input_width = truncate(1, ((u64)(input_frame_width - inw)) <<
|
||||
32, input_m);
|
||||
|
||||
div = div_u64((((u64)(irr_steps * (input_frame_width - 1 - inw))) <<
|
||||
32), (right->output_width - 1));
|
||||
right->irr = truncate(0, div, 1);
|
||||
temp = truncate(0, ((u64)left->irr) * ((((u64)1) << 32) + dirr), 1);
|
||||
if (temp < right->irr)
|
||||
right->irr = temp;
|
||||
div = div_u64(((u64)((right->output_width - 1) * right->irr) <<
|
||||
32), irr_steps);
|
||||
difwr = (u64)(input_frame_width - 1 - inw) - div;
|
||||
|
||||
|
||||
div = div_u64((difwr + (((u64)input_f) << 32)), 2);
|
||||
left->input_column = truncate(0, div, input_f);
|
||||
|
||||
/* This splits the truncated input columns evenly */
|
||||
/* between the left and right margins */
|
||||
right->input_column = left->input_column + inw;
|
||||
left->output_column = 0;
|
||||
right->output_column = onw;
|
||||
if (left->input_width > left->output_width) {
|
||||
if (calc_split_resize_coeffs(left->input_width,
|
||||
left->output_width,
|
||||
&resize_coeff,
|
||||
&downsize_coeff) < 0)
|
||||
return -EINVAL;
|
||||
left->irr = (downsize_coeff << 14) | resize_coeff;
|
||||
}
|
||||
if (right->input_width > right->output_width) {
|
||||
if (calc_split_resize_coeffs(right->input_width,
|
||||
right->output_width,
|
||||
&resize_coeff,
|
||||
&downsize_coeff) < 0)
|
||||
return -EINVAL;
|
||||
right->irr = (downsize_coeff << 14) | resize_coeff;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_calc_stripes_sizes);
|
|
@ -0,0 +1,816 @@
|
|||
/*
|
||||
* Copyright 2008-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file ipu_capture.c
|
||||
*
|
||||
* @brief IPU capture dase functions
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ipu-v3.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "ipu_prv.h"
|
||||
#include "ipu_regs.h"
|
||||
|
||||
/*!
|
||||
* _ipu_csi_mclk_set
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param pixel_clk desired pixel clock frequency in Hz
|
||||
* @param csi csi 0 or csi 1
|
||||
*
|
||||
* @return Returns 0 on success or negative error code on fail
|
||||
*/
|
||||
int _ipu_csi_mclk_set(struct ipu_soc *ipu, uint32_t pixel_clk, uint32_t csi)
|
||||
{
|
||||
uint32_t temp;
|
||||
uint32_t div_ratio;
|
||||
|
||||
div_ratio = (clk_get_rate(ipu->ipu_clk) / pixel_clk) - 1;
|
||||
|
||||
if (div_ratio > 0xFF || div_ratio < 0) {
|
||||
dev_dbg(ipu->dev, "value of pixel_clk extends normal range\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
temp = ipu_csi_read(ipu, csi, CSI_SENS_CONF);
|
||||
temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
|
||||
ipu_csi_write(ipu, csi, temp |
|
||||
(div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
|
||||
CSI_SENS_CONF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* ipu_csi_init_interface
|
||||
* Sets initial values for the CSI registers.
|
||||
* The width and height of the sensor and the actual frame size will be
|
||||
* set to the same values.
|
||||
* @param ipu ipu handler
|
||||
* @param width Sensor width
|
||||
* @param height Sensor height
|
||||
* @param pixel_fmt pixel format
|
||||
* @param cfg_param ipu_csi_signal_cfg_t structure
|
||||
* @param csi csi 0 or csi 1
|
||||
*
|
||||
* @return 0 for success, -EINVAL for error
|
||||
*/
|
||||
int32_t
|
||||
ipu_csi_init_interface(struct ipu_soc *ipu, uint16_t width, uint16_t height,
|
||||
uint32_t pixel_fmt, ipu_csi_signal_cfg_t cfg_param)
|
||||
{
|
||||
uint32_t data = 0;
|
||||
uint32_t csi = cfg_param.csi;
|
||||
|
||||
/* Set SENS_DATA_FORMAT bits (8, 9 and 10)
|
||||
RGB or YUV444 is 0 which is current value in data so not set
|
||||
explicitly
|
||||
This is also the default value if attempts are made to set it to
|
||||
something invalid. */
|
||||
switch (pixel_fmt) {
|
||||
case IPU_PIX_FMT_YUYV:
|
||||
cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
|
||||
break;
|
||||
case IPU_PIX_FMT_UYVY:
|
||||
cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
|
||||
break;
|
||||
case IPU_PIX_FMT_RGB24:
|
||||
case IPU_PIX_FMT_BGR24:
|
||||
cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
|
||||
break;
|
||||
case IPU_PIX_FMT_GENERIC:
|
||||
case IPU_PIX_FMT_GENERIC_16:
|
||||
cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
|
||||
break;
|
||||
case IPU_PIX_FMT_RGB565:
|
||||
cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
|
||||
break;
|
||||
case IPU_PIX_FMT_RGB555:
|
||||
cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set the CSI_SENS_CONF register remaining fields */
|
||||
data |= cfg_param.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
|
||||
cfg_param.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
|
||||
cfg_param.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
|
||||
cfg_param.Vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
|
||||
cfg_param.Hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
|
||||
cfg_param.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
|
||||
cfg_param.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
|
||||
cfg_param.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
|
||||
cfg_param.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
|
||||
cfg_param.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
|
||||
cfg_param.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
|
||||
|
||||
_ipu_get(ipu);
|
||||
|
||||
mutex_lock(&ipu->mutex_lock);
|
||||
|
||||
ipu_csi_write(ipu, csi, data, CSI_SENS_CONF);
|
||||
|
||||
/* Setup sensor frame size */
|
||||
ipu_csi_write(ipu, csi, (width - 1) | (height - 1) << 16, CSI_SENS_FRM_SIZE);
|
||||
|
||||
/* Set CCIR registers */
|
||||
if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) {
|
||||
ipu_csi_write(ipu, csi, 0x40030, CSI_CCIR_CODE_1);
|
||||
ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
|
||||
} else if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED) {
|
||||
if (width == 720 && height == 625) {
|
||||
/* PAL case */
|
||||
/*
|
||||
* Field0BlankEnd = 0x6, Field0BlankStart = 0x2,
|
||||
* Field0ActiveEnd = 0x4, Field0ActiveStart = 0
|
||||
*/
|
||||
ipu_csi_write(ipu, csi, 0x40596, CSI_CCIR_CODE_1);
|
||||
/*
|
||||
* Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
|
||||
* Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
|
||||
*/
|
||||
ipu_csi_write(ipu, csi, 0xD07DF, CSI_CCIR_CODE_2);
|
||||
|
||||
ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
|
||||
|
||||
} else if (width == 720 && height == 525) {
|
||||
/* NTSC case */
|
||||
/*
|
||||
* Field0BlankEnd = 0x7, Field0BlankStart = 0x3,
|
||||
* Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1
|
||||
*/
|
||||
ipu_csi_write(ipu, csi, 0xD07DF, CSI_CCIR_CODE_1);
|
||||
/*
|
||||
* Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
|
||||
* Field1ActiveEnd = 0x4, Field1ActiveStart = 0
|
||||
*/
|
||||
ipu_csi_write(ipu, csi, 0x40596, CSI_CCIR_CODE_2);
|
||||
ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
|
||||
} else {
|
||||
dev_err(ipu->dev, "Unsupported CCIR656 interlaced "
|
||||
"video mode\n");
|
||||
mutex_unlock(&ipu->mutex_lock);
|
||||
_ipu_put(ipu);
|
||||
return -EINVAL;
|
||||
}
|
||||
_ipu_csi_ccir_err_detection_enable(ipu, csi);
|
||||
} else if ((cfg_param.clk_mode ==
|
||||
IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR) ||
|
||||
(cfg_param.clk_mode ==
|
||||
IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR) ||
|
||||
(cfg_param.clk_mode ==
|
||||
IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR) ||
|
||||
(cfg_param.clk_mode ==
|
||||
IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR)) {
|
||||
ipu_csi_write(ipu, csi, 0x40030, CSI_CCIR_CODE_1);
|
||||
ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
|
||||
_ipu_csi_ccir_err_detection_enable(ipu, csi);
|
||||
} else if ((cfg_param.clk_mode == IPU_CSI_CLK_MODE_GATED_CLK) ||
|
||||
(cfg_param.clk_mode == IPU_CSI_CLK_MODE_NONGATED_CLK)) {
|
||||
_ipu_csi_ccir_err_detection_disable(ipu, csi);
|
||||
}
|
||||
|
||||
dev_dbg(ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
|
||||
ipu_csi_read(ipu, csi, CSI_SENS_CONF));
|
||||
dev_dbg(ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
|
||||
ipu_csi_read(ipu, csi, CSI_ACT_FRM_SIZE));
|
||||
|
||||
mutex_unlock(&ipu->mutex_lock);
|
||||
|
||||
_ipu_put(ipu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_csi_init_interface);
|
||||
|
||||
/*!
|
||||
* ipu_csi_get_sensor_protocol
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param csi csi 0 or csi 1
|
||||
*
|
||||
* @return Returns sensor protocol
|
||||
*/
|
||||
int32_t ipu_csi_get_sensor_protocol(struct ipu_soc *ipu, uint32_t csi)
|
||||
{
|
||||
int ret;
|
||||
_ipu_get(ipu);
|
||||
ret = (ipu_csi_read(ipu, csi, CSI_SENS_CONF) &
|
||||
CSI_SENS_CONF_SENS_PRTCL_MASK) >>
|
||||
CSI_SENS_CONF_SENS_PRTCL_SHIFT;
|
||||
_ipu_put(ipu);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_csi_get_sensor_protocol);
|
||||
|
||||
/*!
|
||||
* ipu_csi_enable_mclk
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param csi csi 0 or csi 1
|
||||
* @param flag true to enable mclk, false to disable mclk
|
||||
* @param wait true to wait 100ms make clock stable, false not wait
|
||||
*
|
||||
* @return Returns 0 on success
|
||||
*/
|
||||
int ipu_csi_enable_mclk(struct ipu_soc *ipu, int csi, bool flag, bool wait)
|
||||
{
|
||||
/* Return immediately if there is no csi_clk to manage */
|
||||
if (ipu->csi_clk[csi] == NULL)
|
||||
return 0;
|
||||
|
||||
if (flag) {
|
||||
clk_enable(ipu->csi_clk[csi]);
|
||||
if (wait == true)
|
||||
msleep(10);
|
||||
} else {
|
||||
clk_disable(ipu->csi_clk[csi]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_csi_enable_mclk);
|
||||
|
||||
/*!
|
||||
* ipu_csi_get_window_size
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param width pointer to window width
|
||||
* @param height pointer to window height
|
||||
* @param csi csi 0 or csi 1
|
||||
*/
|
||||
void ipu_csi_get_window_size(struct ipu_soc *ipu, uint32_t *width, uint32_t *height, uint32_t csi)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
_ipu_get(ipu);
|
||||
|
||||
mutex_lock(&ipu->mutex_lock);
|
||||
|
||||
reg = ipu_csi_read(ipu, csi, CSI_ACT_FRM_SIZE);
|
||||
*width = (reg & 0xFFFF) + 1;
|
||||
*height = (reg >> 16 & 0xFFFF) + 1;
|
||||
|
||||
mutex_unlock(&ipu->mutex_lock);
|
||||
|
||||
_ipu_put(ipu);
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_csi_get_window_size);
|
||||
|
||||
/*!
|
||||
* ipu_csi_set_window_size
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param width window width
|
||||
* @param height window height
|
||||
* @param csi csi 0 or csi 1
|
||||
*/
|
||||
void ipu_csi_set_window_size(struct ipu_soc *ipu, uint32_t width, uint32_t height, uint32_t csi)
|
||||
{
|
||||
_ipu_get(ipu);
|
||||
|
||||
mutex_lock(&ipu->mutex_lock);
|
||||
|
||||
ipu_csi_write(ipu, csi, (width - 1) | (height - 1) << 16, CSI_ACT_FRM_SIZE);
|
||||
|
||||
mutex_unlock(&ipu->mutex_lock);
|
||||
|
||||
_ipu_put(ipu);
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_csi_set_window_size);
|
||||
|
||||
/*!
|
||||
* ipu_csi_set_window_pos
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param left uint32 window x start
|
||||
* @param top uint32 window y start
|
||||
* @param csi csi 0 or csi 1
|
||||
*/
|
||||
void ipu_csi_set_window_pos(struct ipu_soc *ipu, uint32_t left, uint32_t top, uint32_t csi)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
_ipu_get(ipu);
|
||||
|
||||
mutex_lock(&ipu->mutex_lock);
|
||||
|
||||
temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
|
||||
temp &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
|
||||
temp |= ((top << CSI_VSC_SHIFT) | (left << CSI_HSC_SHIFT));
|
||||
ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
|
||||
|
||||
mutex_unlock(&ipu->mutex_lock);
|
||||
|
||||
_ipu_put(ipu);
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_csi_set_window_pos);
|
||||
|
||||
/*!
|
||||
* _ipu_csi_horizontal_downsize_enable
|
||||
* Enable horizontal downsizing(decimation) by 2.
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param csi csi 0 or csi 1
|
||||
*/
|
||||
void _ipu_csi_horizontal_downsize_enable(struct ipu_soc *ipu, uint32_t csi)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
|
||||
temp |= CSI_HORI_DOWNSIZE_EN;
|
||||
ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
|
||||
}
|
||||
|
||||
/*!
|
||||
* _ipu_csi_horizontal_downsize_disable
|
||||
* Disable horizontal downsizing(decimation) by 2.
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param csi csi 0 or csi 1
|
||||
*/
|
||||
void _ipu_csi_horizontal_downsize_disable(struct ipu_soc *ipu, uint32_t csi)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
|
||||
temp &= ~CSI_HORI_DOWNSIZE_EN;
|
||||
ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
|
||||
}
|
||||
|
||||
/*!
|
||||
* _ipu_csi_vertical_downsize_enable
|
||||
* Enable vertical downsizing(decimation) by 2.
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param csi csi 0 or csi 1
|
||||
*/
|
||||
void _ipu_csi_vertical_downsize_enable(struct ipu_soc *ipu, uint32_t csi)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
|
||||
temp |= CSI_VERT_DOWNSIZE_EN;
|
||||
ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
|
||||
}
|
||||
|
||||
/*!
|
||||
* _ipu_csi_vertical_downsize_disable
|
||||
* Disable vertical downsizing(decimation) by 2.
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param csi csi 0 or csi 1
|
||||
*/
|
||||
void _ipu_csi_vertical_downsize_disable(struct ipu_soc *ipu, uint32_t csi)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
|
||||
temp &= ~CSI_VERT_DOWNSIZE_EN;
|
||||
ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
|
||||
}
|
||||
|
||||
/*!
|
||||
* _ipu_csi_set_test_generator
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param active 1 for active and 0 for inactive
|
||||
* @param r_value red value for the generated pattern of even pixel
|
||||
* @param g_value green value for the generated pattern of even
|
||||
* pixel
|
||||
* @param b_value blue value for the generated pattern of even pixel
|
||||
* @param pixel_clk desired pixel clock frequency in Hz
|
||||
* @param csi csi 0 or csi 1
|
||||
*/
|
||||
void _ipu_csi_set_test_generator(struct ipu_soc *ipu, bool active, uint32_t r_value,
|
||||
uint32_t g_value, uint32_t b_value, uint32_t pix_clk, uint32_t csi)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
temp = ipu_csi_read(ipu, csi, CSI_TST_CTRL);
|
||||
|
||||
if (active == false) {
|
||||
temp &= ~CSI_TEST_GEN_MODE_EN;
|
||||
ipu_csi_write(ipu, csi, temp, CSI_TST_CTRL);
|
||||
} else {
|
||||
/* Set sensb_mclk div_ratio*/
|
||||
_ipu_csi_mclk_set(ipu, pix_clk, csi);
|
||||
|
||||
temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
|
||||
CSI_TEST_GEN_B_MASK);
|
||||
temp |= CSI_TEST_GEN_MODE_EN;
|
||||
temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
|
||||
(g_value << CSI_TEST_GEN_G_SHIFT) |
|
||||
(b_value << CSI_TEST_GEN_B_SHIFT);
|
||||
ipu_csi_write(ipu, csi, temp, CSI_TST_CTRL);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* _ipu_csi_ccir_err_detection_en
|
||||
* Enable error detection and correction for
|
||||
* CCIR interlaced mode with protection bit.
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param csi csi 0 or csi 1
|
||||
*/
|
||||
void _ipu_csi_ccir_err_detection_enable(struct ipu_soc *ipu, uint32_t csi)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
temp = ipu_csi_read(ipu, csi, CSI_CCIR_CODE_1);
|
||||
temp |= CSI_CCIR_ERR_DET_EN;
|
||||
ipu_csi_write(ipu, csi, temp, CSI_CCIR_CODE_1);
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* _ipu_csi_ccir_err_detection_disable
|
||||
* Disable error detection and correction for
|
||||
* CCIR interlaced mode with protection bit.
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param csi csi 0 or csi 1
|
||||
*/
|
||||
void _ipu_csi_ccir_err_detection_disable(struct ipu_soc *ipu, uint32_t csi)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
temp = ipu_csi_read(ipu, csi, CSI_CCIR_CODE_1);
|
||||
temp &= ~CSI_CCIR_ERR_DET_EN;
|
||||
ipu_csi_write(ipu, csi, temp, CSI_CCIR_CODE_1);
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* _ipu_csi_set_mipi_di
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param num MIPI data identifier 0-3 handled by CSI
|
||||
* @param di_val data identifier value
|
||||
* @param csi csi 0 or csi 1
|
||||
*
|
||||
* @return Returns 0 on success or negative error code on fail
|
||||
*/
|
||||
int _ipu_csi_set_mipi_di(struct ipu_soc *ipu, uint32_t num, uint32_t di_val, uint32_t csi)
|
||||
{
|
||||
uint32_t temp;
|
||||
int retval = 0;
|
||||
|
||||
if (di_val > 0xFFL) {
|
||||
retval = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
temp = ipu_csi_read(ipu, csi, CSI_MIPI_DI);
|
||||
|
||||
switch (num) {
|
||||
case IPU_CSI_MIPI_DI0:
|
||||
temp &= ~CSI_MIPI_DI0_MASK;
|
||||
temp |= (di_val << CSI_MIPI_DI0_SHIFT);
|
||||
ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
|
||||
break;
|
||||
case IPU_CSI_MIPI_DI1:
|
||||
temp &= ~CSI_MIPI_DI1_MASK;
|
||||
temp |= (di_val << CSI_MIPI_DI1_SHIFT);
|
||||
ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
|
||||
break;
|
||||
case IPU_CSI_MIPI_DI2:
|
||||
temp &= ~CSI_MIPI_DI2_MASK;
|
||||
temp |= (di_val << CSI_MIPI_DI2_SHIFT);
|
||||
ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
|
||||
break;
|
||||
case IPU_CSI_MIPI_DI3:
|
||||
temp &= ~CSI_MIPI_DI3_MASK;
|
||||
temp |= (di_val << CSI_MIPI_DI3_SHIFT);
|
||||
ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
|
||||
break;
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
}
|
||||
|
||||
err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
* _ipu_csi_set_skip_isp
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param skip select frames to be skipped and set the
|
||||
* correspond bits to 1
|
||||
* @param max_ratio number of frames in a skipping set and the
|
||||
* maximum value of max_ratio is 5
|
||||
* @param csi csi 0 or csi 1
|
||||
*
|
||||
* @return Returns 0 on success or negative error code on fail
|
||||
*/
|
||||
int _ipu_csi_set_skip_isp(struct ipu_soc *ipu, uint32_t skip, uint32_t max_ratio, uint32_t csi)
|
||||
{
|
||||
uint32_t temp;
|
||||
int retval = 0;
|
||||
|
||||
if (max_ratio > 5) {
|
||||
retval = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
temp = ipu_csi_read(ipu, csi, CSI_SKIP);
|
||||
temp &= ~(CSI_MAX_RATIO_SKIP_ISP_MASK | CSI_SKIP_ISP_MASK);
|
||||
temp |= (max_ratio << CSI_MAX_RATIO_SKIP_ISP_SHIFT) |
|
||||
(skip << CSI_SKIP_ISP_SHIFT);
|
||||
ipu_csi_write(ipu, csi, temp, CSI_SKIP);
|
||||
|
||||
err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
* _ipu_csi_set_skip_smfc
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param skip select frames to be skipped and set the
|
||||
* correspond bits to 1
|
||||
* @param max_ratio number of frames in a skipping set and the
|
||||
* maximum value of max_ratio is 5
|
||||
* @param id csi to smfc skipping id
|
||||
* @param csi csi 0 or csi 1
|
||||
*
|
||||
* @return Returns 0 on success or negative error code on fail
|
||||
*/
|
||||
int _ipu_csi_set_skip_smfc(struct ipu_soc *ipu, uint32_t skip,
|
||||
uint32_t max_ratio, uint32_t id, uint32_t csi)
|
||||
{
|
||||
uint32_t temp;
|
||||
int retval = 0;
|
||||
|
||||
if (max_ratio > 5 || id > 3) {
|
||||
retval = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
temp = ipu_csi_read(ipu, csi, CSI_SKIP);
|
||||
temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
|
||||
CSI_SKIP_SMFC_MASK);
|
||||
temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
|
||||
(id << CSI_ID_2_SKIP_SHIFT) |
|
||||
(skip << CSI_SKIP_SMFC_SHIFT);
|
||||
ipu_csi_write(ipu, csi, temp, CSI_SKIP);
|
||||
|
||||
err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
* _ipu_smfc_init
|
||||
* Map CSI frames to IDMAC channels.
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param channel IDMAC channel 0-3
|
||||
* @param mipi_id mipi id number 0-3
|
||||
* @param csi csi0 or csi1
|
||||
*/
|
||||
void _ipu_smfc_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t mipi_id, uint32_t csi)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
temp = ipu_smfc_read(ipu, SMFC_MAP);
|
||||
|
||||
switch (channel) {
|
||||
case CSI_MEM0:
|
||||
temp &= ~SMFC_MAP_CH0_MASK;
|
||||
temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH0_SHIFT;
|
||||
break;
|
||||
case CSI_MEM1:
|
||||
temp &= ~SMFC_MAP_CH1_MASK;
|
||||
temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH1_SHIFT;
|
||||
break;
|
||||
case CSI_MEM2:
|
||||
temp &= ~SMFC_MAP_CH2_MASK;
|
||||
temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH2_SHIFT;
|
||||
break;
|
||||
case CSI_MEM3:
|
||||
temp &= ~SMFC_MAP_CH3_MASK;
|
||||
temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH3_SHIFT;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
ipu_smfc_write(ipu, temp, SMFC_MAP);
|
||||
}
|
||||
|
||||
/*!
|
||||
* _ipu_smfc_set_wmc
|
||||
* Caution: The number of required channels, the enabled channels
|
||||
* and the FIFO size per channel are configured restrictedly.
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param channel IDMAC channel 0-3
|
||||
* @param set set 1 or clear 0
|
||||
* @param level water mark level when FIFO is on the
|
||||
* relative size
|
||||
*/
|
||||
void _ipu_smfc_set_wmc(struct ipu_soc *ipu, ipu_channel_t channel, bool set, uint32_t level)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
temp = ipu_smfc_read(ipu, SMFC_WMC);
|
||||
|
||||
switch (channel) {
|
||||
case CSI_MEM0:
|
||||
if (set == true) {
|
||||
temp &= ~SMFC_WM0_SET_MASK;
|
||||
temp |= level << SMFC_WM0_SET_SHIFT;
|
||||
} else {
|
||||
temp &= ~SMFC_WM0_CLR_MASK;
|
||||
temp |= level << SMFC_WM0_CLR_SHIFT;
|
||||
}
|
||||
break;
|
||||
case CSI_MEM1:
|
||||
if (set == true) {
|
||||
temp &= ~SMFC_WM1_SET_MASK;
|
||||
temp |= level << SMFC_WM1_SET_SHIFT;
|
||||
} else {
|
||||
temp &= ~SMFC_WM1_CLR_MASK;
|
||||
temp |= level << SMFC_WM1_CLR_SHIFT;
|
||||
}
|
||||
break;
|
||||
case CSI_MEM2:
|
||||
if (set == true) {
|
||||
temp &= ~SMFC_WM2_SET_MASK;
|
||||
temp |= level << SMFC_WM2_SET_SHIFT;
|
||||
} else {
|
||||
temp &= ~SMFC_WM2_CLR_MASK;
|
||||
temp |= level << SMFC_WM2_CLR_SHIFT;
|
||||
}
|
||||
break;
|
||||
case CSI_MEM3:
|
||||
if (set == true) {
|
||||
temp &= ~SMFC_WM3_SET_MASK;
|
||||
temp |= level << SMFC_WM3_SET_SHIFT;
|
||||
} else {
|
||||
temp &= ~SMFC_WM3_CLR_MASK;
|
||||
temp |= level << SMFC_WM3_CLR_SHIFT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
ipu_smfc_write(ipu, temp, SMFC_WMC);
|
||||
}
|
||||
|
||||
/*!
|
||||
* _ipu_smfc_set_burst_size
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param channel IDMAC channel 0-3
|
||||
* @param bs burst size of IDMAC channel,
|
||||
* the value programmed here shoud be BURST_SIZE-1
|
||||
*/
|
||||
void _ipu_smfc_set_burst_size(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t bs)
|
||||
{
|
||||
uint32_t temp;
|
||||
|
||||
temp = ipu_smfc_read(ipu, SMFC_BS);
|
||||
|
||||
switch (channel) {
|
||||
case CSI_MEM0:
|
||||
temp &= ~SMFC_BS0_MASK;
|
||||
temp |= bs << SMFC_BS0_SHIFT;
|
||||
break;
|
||||
case CSI_MEM1:
|
||||
temp &= ~SMFC_BS1_MASK;
|
||||
temp |= bs << SMFC_BS1_SHIFT;
|
||||
break;
|
||||
case CSI_MEM2:
|
||||
temp &= ~SMFC_BS2_MASK;
|
||||
temp |= bs << SMFC_BS2_SHIFT;
|
||||
break;
|
||||
case CSI_MEM3:
|
||||
temp &= ~SMFC_BS3_MASK;
|
||||
temp |= bs << SMFC_BS3_SHIFT;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
ipu_smfc_write(ipu, temp, SMFC_BS);
|
||||
}
|
||||
|
||||
/*!
|
||||
* _ipu_csi_init
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param channel IDMAC channel
|
||||
* @param csi csi 0 or csi 1
|
||||
*
|
||||
* @return Returns 0 on success or negative error code on fail
|
||||
*/
|
||||
int _ipu_csi_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t csi)
|
||||
{
|
||||
uint32_t csi_sens_conf, csi_dest;
|
||||
int retval = 0;
|
||||
|
||||
switch (channel) {
|
||||
case CSI_MEM0:
|
||||
case CSI_MEM1:
|
||||
case CSI_MEM2:
|
||||
case CSI_MEM3:
|
||||
csi_dest = CSI_DATA_DEST_IDMAC;
|
||||
break;
|
||||
case CSI_PRP_ENC_MEM:
|
||||
case CSI_PRP_VF_MEM:
|
||||
csi_dest = CSI_DATA_DEST_IC;
|
||||
break;
|
||||
default:
|
||||
retval = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
csi_sens_conf = ipu_csi_read(ipu, csi, CSI_SENS_CONF);
|
||||
csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
|
||||
ipu_csi_write(ipu, csi, csi_sens_conf | (csi_dest <<
|
||||
CSI_SENS_CONF_DATA_DEST_SHIFT), CSI_SENS_CONF);
|
||||
err:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*!
|
||||
* csi_irq_handler
|
||||
*
|
||||
* @param irq interrupt id
|
||||
* @param dev_id pointer to ipu handler
|
||||
*
|
||||
* @return Returns if irq is handled
|
||||
*/
|
||||
static irqreturn_t csi_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct ipu_soc *ipu = dev_id;
|
||||
struct completion *comp = &ipu->csi_comp;
|
||||
|
||||
complete(comp);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*!
|
||||
* _ipu_csi_wait4eof
|
||||
*
|
||||
* @param ipu ipu handler
|
||||
* @param channel IDMAC channel
|
||||
*
|
||||
*/
|
||||
void _ipu_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel)
|
||||
{
|
||||
int ret;
|
||||
int irq = 0;
|
||||
|
||||
if (channel == CSI_MEM0)
|
||||
irq = IPU_IRQ_CSI0_OUT_EOF;
|
||||
else if (channel == CSI_MEM1)
|
||||
irq = IPU_IRQ_CSI1_OUT_EOF;
|
||||
else if (channel == CSI_MEM2)
|
||||
irq = IPU_IRQ_CSI2_OUT_EOF;
|
||||
else if (channel == CSI_MEM3)
|
||||
irq = IPU_IRQ_CSI3_OUT_EOF;
|
||||
else if (channel == CSI_PRP_ENC_MEM)
|
||||
irq = IPU_IRQ_PRP_ENC_OUT_EOF;
|
||||
else if (channel == CSI_PRP_VF_MEM)
|
||||
irq = IPU_IRQ_PRP_VF_OUT_EOF;
|
||||
else{
|
||||
dev_err(ipu->dev, "Not a CSI channel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
init_completion(&ipu->csi_comp);
|
||||
ret = ipu_request_irq(ipu, irq, csi_irq_handler, 0, NULL, ipu);
|
||||
if (ret < 0) {
|
||||
dev_err(ipu->dev, "CSI irq %d in use\n", irq);
|
||||
return;
|
||||
}
|
||||
ret = wait_for_completion_timeout(&ipu->csi_comp, msecs_to_jiffies(500));
|
||||
ipu_free_irq(ipu, irq, ipu);
|
||||
dev_dbg(ipu->dev, "CSI stop timeout - %d * 10ms\n", 5 - ret);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,924 @@
|
|||
/*
|
||||
* Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* @file ipu_ic.c
|
||||
*
|
||||
* @brief IPU IC functions
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ipu-v3.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#include "ipu_param_mem.h"
|
||||
#include "ipu_regs.h"
|
||||
|
||||
enum {
|
||||
IC_TASK_VIEWFINDER,
|
||||
IC_TASK_ENCODER,
|
||||
IC_TASK_POST_PROCESSOR
|
||||
};
|
||||
|
||||
static void _init_csc(struct ipu_soc *ipu, uint8_t ic_task, ipu_color_space_t in_format,
|
||||
ipu_color_space_t out_format, int csc_index);
|
||||
|
||||
static int _calc_resize_coeffs(struct ipu_soc *ipu,
|
||||
uint32_t inSize, uint32_t outSize,
|
||||
uint32_t *resizeCoeff,
|
||||
uint32_t *downsizeCoeff);
|
||||
|
||||
void _ipu_vdi_set_top_field_man(struct ipu_soc *ipu, bool top_field_0)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = ipu_vdi_read(ipu, VDI_C);
|
||||
if (top_field_0)
|
||||
reg &= ~VDI_C_TOP_FIELD_MAN_1;
|
||||
else
|
||||
reg |= VDI_C_TOP_FIELD_MAN_1;
|
||||
ipu_vdi_write(ipu, reg, VDI_C);
|
||||
}
|
||||
|
||||
void _ipu_vdi_set_motion(struct ipu_soc *ipu, ipu_motion_sel motion_sel)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = ipu_vdi_read(ipu, VDI_C);
|
||||
reg &= ~(VDI_C_MOT_SEL_FULL | VDI_C_MOT_SEL_MED | VDI_C_MOT_SEL_LOW);
|
||||
if (motion_sel == HIGH_MOTION)
|
||||
reg |= VDI_C_MOT_SEL_FULL;
|
||||
else if (motion_sel == MED_MOTION)
|
||||
reg |= VDI_C_MOT_SEL_MED;
|
||||
else
|
||||
reg |= VDI_C_MOT_SEL_LOW;
|
||||
|
||||
ipu_vdi_write(ipu, reg, VDI_C);
|
||||
dev_dbg(ipu->dev, "VDI_C = \t0x%08X\n", reg);
|
||||
}
|
||||
|
||||
void ic_dump_register(struct ipu_soc *ipu)
|
||||
{
|
||||
printk(KERN_DEBUG "IC_CONF = \t0x%08X\n", ipu_ic_read(ipu, IC_CONF));
|
||||
printk(KERN_DEBUG "IC_PRP_ENC_RSC = \t0x%08X\n",
|
||||
ipu_ic_read(ipu, IC_PRP_ENC_RSC));
|
||||
printk(KERN_DEBUG "IC_PRP_VF_RSC = \t0x%08X\n",
|
||||
ipu_ic_read(ipu, IC_PRP_VF_RSC));
|
||||
printk(KERN_DEBUG "IC_PP_RSC = \t0x%08X\n", ipu_ic_read(ipu, IC_PP_RSC));
|
||||
printk(KERN_DEBUG "IC_IDMAC_1 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_1));
|
||||
printk(KERN_DEBUG "IC_IDMAC_2 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_2));
|
||||
printk(KERN_DEBUG "IC_IDMAC_3 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_3));
|
||||
}
|
||||
|
||||
void _ipu_ic_enable_task(struct ipu_soc *ipu, ipu_channel_t channel)
|
||||
{
|
||||
uint32_t ic_conf;
|
||||
|
||||
ic_conf = ipu_ic_read(ipu, IC_CONF);
|
||||
switch (channel) {
|
||||
case CSI_PRP_VF_MEM:
|
||||
case MEM_PRP_VF_MEM:
|
||||
ic_conf |= IC_CONF_PRPVF_EN;
|
||||
break;
|
||||
case MEM_VDI_PRP_VF_MEM:
|
||||
ic_conf |= IC_CONF_PRPVF_EN;
|
||||
break;
|
||||
case MEM_VDI_MEM:
|
||||
ic_conf |= IC_CONF_PRPVF_EN | IC_CONF_RWS_EN ;
|
||||
break;
|
||||
case MEM_ROT_VF_MEM:
|
||||
ic_conf |= IC_CONF_PRPVF_ROT_EN;
|
||||
break;
|
||||
case CSI_PRP_ENC_MEM:
|
||||
case MEM_PRP_ENC_MEM:
|
||||
ic_conf |= IC_CONF_PRPENC_EN;
|
||||
break;
|
||||
case MEM_ROT_ENC_MEM:
|
||||
ic_conf |= IC_CONF_PRPENC_ROT_EN;
|
||||
break;
|
||||
case MEM_PP_MEM:
|
||||
ic_conf |= IC_CONF_PP_EN;
|
||||
break;
|
||||
case MEM_ROT_PP_MEM:
|
||||
ic_conf |= IC_CONF_PP_ROT_EN;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ipu_ic_write(ipu, ic_conf, IC_CONF);
|
||||
}
|
||||
|
||||
void _ipu_ic_disable_task(struct ipu_soc *ipu, ipu_channel_t channel)
|
||||
{
|
||||
uint32_t ic_conf;
|
||||
|
||||
ic_conf = ipu_ic_read(ipu, IC_CONF);
|
||||
switch (channel) {
|
||||
case CSI_PRP_VF_MEM:
|
||||
case MEM_PRP_VF_MEM:
|
||||
ic_conf &= ~IC_CONF_PRPVF_EN;
|
||||
break;
|
||||
case MEM_VDI_PRP_VF_MEM:
|
||||
ic_conf &= ~IC_CONF_PRPVF_EN;
|
||||
break;
|
||||
case MEM_VDI_MEM:
|
||||
ic_conf &= ~(IC_CONF_PRPVF_EN | IC_CONF_RWS_EN);
|
||||
break;
|
||||
case MEM_ROT_VF_MEM:
|
||||
ic_conf &= ~IC_CONF_PRPVF_ROT_EN;
|
||||
break;
|
||||
case CSI_PRP_ENC_MEM:
|
||||
case MEM_PRP_ENC_MEM:
|
||||
ic_conf &= ~IC_CONF_PRPENC_EN;
|
||||
break;
|
||||
case MEM_ROT_ENC_MEM:
|
||||
ic_conf &= ~IC_CONF_PRPENC_ROT_EN;
|
||||
break;
|
||||
case MEM_PP_MEM:
|
||||
ic_conf &= ~IC_CONF_PP_EN;
|
||||
break;
|
||||
case MEM_ROT_PP_MEM:
|
||||
ic_conf &= ~IC_CONF_PP_ROT_EN;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ipu_ic_write(ipu, ic_conf, IC_CONF);
|
||||
}
|
||||
|
||||
void _ipu_vdi_init(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params)
|
||||
{
|
||||
uint32_t reg;
|
||||
uint32_t pixel_fmt;
|
||||
uint32_t pix_per_burst;
|
||||
|
||||
reg = ((params->mem_prp_vf_mem.in_height-1) << 16) |
|
||||
(params->mem_prp_vf_mem.in_width-1);
|
||||
ipu_vdi_write(ipu, reg, VDI_FSIZE);
|
||||
|
||||
/* Full motion, only vertical filter is used
|
||||
Burst size is 4 accesses */
|
||||
if (params->mem_prp_vf_mem.in_pixel_fmt ==
|
||||
IPU_PIX_FMT_UYVY ||
|
||||
params->mem_prp_vf_mem.in_pixel_fmt ==
|
||||
IPU_PIX_FMT_YUYV) {
|
||||
pixel_fmt = VDI_C_CH_422;
|
||||
pix_per_burst = 32;
|
||||
} else {
|
||||
pixel_fmt = VDI_C_CH_420;
|
||||
pix_per_burst = 64;
|
||||
}
|
||||
|
||||
reg = ipu_vdi_read(ipu, VDI_C);
|
||||
reg |= pixel_fmt;
|
||||
switch (channel) {
|
||||
case MEM_VDI_PRP_VF_MEM:
|
||||
reg |= VDI_C_BURST_SIZE2_4;
|
||||
break;
|
||||
case MEM_VDI_PRP_VF_MEM_P:
|
||||
reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_SET_1 | VDI_C_VWM1_CLR_2;
|
||||
break;
|
||||
case MEM_VDI_PRP_VF_MEM_N:
|
||||
reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_SET_1 | VDI_C_VWM3_CLR_2;
|
||||
break;
|
||||
|
||||
case MEM_VDI_MEM:
|
||||
reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
|
||||
<< VDI_C_BURST_SIZE2_OFFSET;
|
||||
break;
|
||||
case MEM_VDI_MEM_P:
|
||||
reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
|
||||
<< VDI_C_BURST_SIZE1_OFFSET;
|
||||
reg |= VDI_C_VWM1_SET_2 | VDI_C_VWM1_CLR_2;
|
||||
break;
|
||||
case MEM_VDI_MEM_N:
|
||||
reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
|
||||
<< VDI_C_BURST_SIZE3_OFFSET;
|
||||
reg |= VDI_C_VWM3_SET_2 | VDI_C_VWM3_CLR_2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ipu_vdi_write(ipu, reg, VDI_C);
|
||||
|
||||
if (params->mem_prp_vf_mem.field_fmt == IPU_DEINTERLACE_FIELD_TOP)
|
||||
_ipu_vdi_set_top_field_man(ipu, true);
|
||||
else if (params->mem_prp_vf_mem.field_fmt == IPU_DEINTERLACE_FIELD_BOTTOM)
|
||||
_ipu_vdi_set_top_field_man(ipu, false);
|
||||
|
||||
_ipu_vdi_set_motion(ipu, params->mem_prp_vf_mem.motion_sel);
|
||||
|
||||
reg = ipu_ic_read(ipu, IC_CONF);
|
||||
reg &= ~IC_CONF_RWS_EN;
|
||||
ipu_ic_write(ipu, reg, IC_CONF);
|
||||
}
|
||||
|
||||
void _ipu_vdi_uninit(struct ipu_soc *ipu)
|
||||
{
|
||||
ipu_vdi_write(ipu, 0, VDI_FSIZE);
|
||||
ipu_vdi_write(ipu, 0, VDI_C);
|
||||
}
|
||||
|
||||
int _ipu_ic_init_prpvf(struct ipu_soc *ipu, ipu_channel_params_t *params,
|
||||
bool src_is_csi)
|
||||
{
|
||||
uint32_t reg, ic_conf;
|
||||
uint32_t downsizeCoeff, resizeCoeff;
|
||||
ipu_color_space_t in_fmt, out_fmt;
|
||||
int ret = 0;
|
||||
|
||||
/* Setup vertical resizing */
|
||||
if (!params->mem_prp_vf_mem.outv_resize_ratio) {
|
||||
ret = _calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_height,
|
||||
params->mem_prp_vf_mem.out_height,
|
||||
&resizeCoeff, &downsizeCoeff);
|
||||
if (ret < 0) {
|
||||
dev_err(ipu->dev, "failed to calculate prpvf height "
|
||||
"scaling coefficients\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
|
||||
} else
|
||||
reg = (params->mem_prp_vf_mem.outv_resize_ratio) << 16;
|
||||
|
||||
/* Setup horizontal resizing */
|
||||
if (!params->mem_prp_vf_mem.outh_resize_ratio) {
|
||||
ret = _calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_width,
|
||||
params->mem_prp_vf_mem.out_width,
|
||||
&resizeCoeff, &downsizeCoeff);
|
||||
if (ret < 0) {
|
||||
dev_err(ipu->dev, "failed to calculate prpvf width "
|
||||
"scaling coefficients\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg |= (downsizeCoeff << 14) | resizeCoeff;
|
||||
} else
|
||||
reg |= params->mem_prp_vf_mem.outh_resize_ratio;
|
||||
|
||||
ipu_ic_write(ipu, reg, IC_PRP_VF_RSC);
|
||||
|
||||
ic_conf = ipu_ic_read(ipu, IC_CONF);
|
||||
|
||||
/* Setup color space conversion */
|
||||
in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_pixel_fmt);
|
||||
out_fmt = format_to_colorspace(params->mem_prp_vf_mem.out_pixel_fmt);
|
||||
if (in_fmt == RGB) {
|
||||
if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
|
||||
/* Enable RGB->YCBCR CSC1 */
|
||||
_init_csc(ipu, IC_TASK_VIEWFINDER, RGB, out_fmt, 1);
|
||||
ic_conf |= IC_CONF_PRPVF_CSC1;
|
||||
}
|
||||
}
|
||||
if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
|
||||
if (out_fmt == RGB) {
|
||||
/* Enable YCBCR->RGB CSC1 */
|
||||
_init_csc(ipu, IC_TASK_VIEWFINDER, YCbCr, RGB, 1);
|
||||
ic_conf |= IC_CONF_PRPVF_CSC1;
|
||||
} else {
|
||||
/* TODO: Support YUV<->YCbCr conversion? */
|
||||
}
|
||||
}
|
||||
|
||||
if (params->mem_prp_vf_mem.graphics_combine_en) {
|
||||
ic_conf |= IC_CONF_PRPVF_CMB;
|
||||
|
||||
if (!(ic_conf & IC_CONF_PRPVF_CSC1)) {
|
||||
/* need transparent CSC1 conversion */
|
||||
_init_csc(ipu, IC_TASK_VIEWFINDER, RGB, RGB, 1);
|
||||
ic_conf |= IC_CONF_PRPVF_CSC1; /* Enable RGB->RGB CSC */
|
||||
}
|
||||
in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_g_pixel_fmt);
|
||||
out_fmt = format_to_colorspace(params->mem_prp_vf_mem.out_pixel_fmt);
|
||||
if (in_fmt == RGB) {
|
||||
if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
|
||||
/* Enable RGB->YCBCR CSC2 */
|
||||
_init_csc(ipu, IC_TASK_VIEWFINDER, RGB, out_fmt, 2);
|
||||
ic_conf |= IC_CONF_PRPVF_CSC2;
|
||||
}
|
||||
}
|
||||
if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
|
||||
if (out_fmt == RGB) {
|
||||
/* Enable YCBCR->RGB CSC2 */
|
||||
_init_csc(ipu, IC_TASK_VIEWFINDER, YCbCr, RGB, 2);
|
||||
ic_conf |= IC_CONF_PRPVF_CSC2;
|
||||
} else {
|
||||
/* TODO: Support YUV<->YCbCr conversion? */
|
||||
}
|
||||
}
|
||||
|
||||
if (params->mem_prp_vf_mem.global_alpha_en) {
|
||||
ic_conf |= IC_CONF_IC_GLB_LOC_A;
|
||||
reg = ipu_ic_read(ipu, IC_CMBP_1);
|
||||
reg &= ~(0xff);
|
||||
reg |= params->mem_prp_vf_mem.alpha;
|
||||
ipu_ic_write(ipu, reg, IC_CMBP_1);
|
||||
} else
|
||||
ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
|
||||
|
||||
if (params->mem_prp_vf_mem.key_color_en) {
|
||||
ic_conf |= IC_CONF_KEY_COLOR_EN;
|
||||
ipu_ic_write(ipu, params->mem_prp_vf_mem.key_color,
|
||||
IC_CMBP_2);
|
||||
} else
|
||||
ic_conf &= ~IC_CONF_KEY_COLOR_EN;
|
||||
} else {
|
||||
ic_conf &= ~IC_CONF_PRPVF_CMB;
|
||||
}
|
||||
|
||||
if (src_is_csi)
|
||||
ic_conf &= ~IC_CONF_RWS_EN;
|
||||
else
|
||||
ic_conf |= IC_CONF_RWS_EN;
|
||||
|
||||
ipu_ic_write(ipu, ic_conf, IC_CONF);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void _ipu_ic_uninit_prpvf(struct ipu_soc *ipu)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = ipu_ic_read(ipu, IC_CONF);
|
||||
reg &= ~(IC_CONF_PRPVF_EN | IC_CONF_PRPVF_CMB |
|
||||
IC_CONF_PRPVF_CSC2 | IC_CONF_PRPVF_CSC1);
|
||||
ipu_ic_write(ipu, reg, IC_CONF);
|
||||
}
|
||||
|
||||
void _ipu_ic_init_rotate_vf(struct ipu_soc *ipu, ipu_channel_params_t *params)
|
||||
{
|
||||
}
|
||||
|
||||
void _ipu_ic_uninit_rotate_vf(struct ipu_soc *ipu)
|
||||
{
|
||||
uint32_t reg;
|
||||
reg = ipu_ic_read(ipu, IC_CONF);
|
||||
reg &= ~IC_CONF_PRPVF_ROT_EN;
|
||||
ipu_ic_write(ipu, reg, IC_CONF);
|
||||
}
|
||||
|
||||
int _ipu_ic_init_prpenc(struct ipu_soc *ipu, ipu_channel_params_t *params,
|
||||
bool src_is_csi)
|
||||
{
|
||||
uint32_t reg, ic_conf;
|
||||
uint32_t downsizeCoeff, resizeCoeff;
|
||||
ipu_color_space_t in_fmt, out_fmt;
|
||||
int ret = 0;
|
||||
|
||||
/* Setup vertical resizing */
|
||||
if (!params->mem_prp_enc_mem.outv_resize_ratio) {
|
||||
ret = _calc_resize_coeffs(ipu,
|
||||
params->mem_prp_enc_mem.in_height,
|
||||
params->mem_prp_enc_mem.out_height,
|
||||
&resizeCoeff, &downsizeCoeff);
|
||||
if (ret < 0) {
|
||||
dev_err(ipu->dev, "failed to calculate prpenc height "
|
||||
"scaling coefficients\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
|
||||
} else
|
||||
reg = (params->mem_prp_enc_mem.outv_resize_ratio) << 16;
|
||||
|
||||
/* Setup horizontal resizing */
|
||||
if (!params->mem_prp_enc_mem.outh_resize_ratio) {
|
||||
ret = _calc_resize_coeffs(ipu, params->mem_prp_enc_mem.in_width,
|
||||
params->mem_prp_enc_mem.out_width,
|
||||
&resizeCoeff, &downsizeCoeff);
|
||||
if (ret < 0) {
|
||||
dev_err(ipu->dev, "failed to calculate prpenc width "
|
||||
"scaling coefficients\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg |= (downsizeCoeff << 14) | resizeCoeff;
|
||||
} else
|
||||
reg |= params->mem_prp_enc_mem.outh_resize_ratio;
|
||||
|
||||
ipu_ic_write(ipu, reg, IC_PRP_ENC_RSC);
|
||||
|
||||
ic_conf = ipu_ic_read(ipu, IC_CONF);
|
||||
|
||||
/* Setup color space conversion */
|
||||
in_fmt = format_to_colorspace(params->mem_prp_enc_mem.in_pixel_fmt);
|
||||
out_fmt = format_to_colorspace(params->mem_prp_enc_mem.out_pixel_fmt);
|
||||
if (in_fmt == RGB) {
|
||||
if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
|
||||
/* Enable RGB->YCBCR CSC1 */
|
||||
_init_csc(ipu, IC_TASK_ENCODER, RGB, out_fmt, 1);
|
||||
ic_conf |= IC_CONF_PRPENC_CSC1;
|
||||
}
|
||||
}
|
||||
if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
|
||||
if (out_fmt == RGB) {
|
||||
/* Enable YCBCR->RGB CSC1 */
|
||||
_init_csc(ipu, IC_TASK_ENCODER, YCbCr, RGB, 1);
|
||||
ic_conf |= IC_CONF_PRPENC_CSC1;
|
||||
} else {
|
||||
/* TODO: Support YUV<->YCbCr conversion? */
|
||||
}
|
||||
}
|
||||
|
||||
if (src_is_csi)
|
||||
ic_conf &= ~IC_CONF_RWS_EN;
|
||||
else
|
||||
ic_conf |= IC_CONF_RWS_EN;
|
||||
|
||||
ipu_ic_write(ipu, ic_conf, IC_CONF);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void _ipu_ic_uninit_prpenc(struct ipu_soc *ipu)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = ipu_ic_read(ipu, IC_CONF);
|
||||
reg &= ~(IC_CONF_PRPENC_EN | IC_CONF_PRPENC_CSC1);
|
||||
ipu_ic_write(ipu, reg, IC_CONF);
|
||||
}
|
||||
|
||||
void _ipu_ic_init_rotate_enc(struct ipu_soc *ipu, ipu_channel_params_t *params)
|
||||
{
|
||||
}
|
||||
|
||||
void _ipu_ic_uninit_rotate_enc(struct ipu_soc *ipu)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = ipu_ic_read(ipu, IC_CONF);
|
||||
reg &= ~(IC_CONF_PRPENC_ROT_EN);
|
||||
ipu_ic_write(ipu, reg, IC_CONF);
|
||||
}
|
||||
|
||||
int _ipu_ic_init_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
|
||||
{
|
||||
uint32_t reg, ic_conf;
|
||||
uint32_t downsizeCoeff, resizeCoeff;
|
||||
ipu_color_space_t in_fmt, out_fmt;
|
||||
int ret = 0;
|
||||
|
||||
/* Setup vertical resizing */
|
||||
if (!params->mem_pp_mem.outv_resize_ratio) {
|
||||
ret = _calc_resize_coeffs(ipu, params->mem_pp_mem.in_height,
|
||||
params->mem_pp_mem.out_height,
|
||||
&resizeCoeff, &downsizeCoeff);
|
||||
if (ret < 0) {
|
||||
dev_err(ipu->dev, "failed to calculate pp height "
|
||||
"scaling coefficients\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
|
||||
} else {
|
||||
reg = (params->mem_pp_mem.outv_resize_ratio) << 16;
|
||||
}
|
||||
|
||||
/* Setup horizontal resizing */
|
||||
if (!params->mem_pp_mem.outh_resize_ratio) {
|
||||
ret = _calc_resize_coeffs(ipu, params->mem_pp_mem.in_width,
|
||||
params->mem_pp_mem.out_width,
|
||||
&resizeCoeff, &downsizeCoeff);
|
||||
if (ret < 0) {
|
||||
dev_err(ipu->dev, "failed to calculate pp width "
|
||||
"scaling coefficients\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
reg |= (downsizeCoeff << 14) | resizeCoeff;
|
||||
} else {
|
||||
reg |= params->mem_pp_mem.outh_resize_ratio;
|
||||
}
|
||||
|
||||
ipu_ic_write(ipu, reg, IC_PP_RSC);
|
||||
|
||||
ic_conf = ipu_ic_read(ipu, IC_CONF);
|
||||
|
||||
/* Setup color space conversion */
|
||||
in_fmt = format_to_colorspace(params->mem_pp_mem.in_pixel_fmt);
|
||||
out_fmt = format_to_colorspace(params->mem_pp_mem.out_pixel_fmt);
|
||||
if (in_fmt == RGB) {
|
||||
if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
|
||||
/* Enable RGB->YCBCR CSC1 */
|
||||
_init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, out_fmt, 1);
|
||||
ic_conf |= IC_CONF_PP_CSC1;
|
||||
}
|
||||
}
|
||||
if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
|
||||
if (out_fmt == RGB) {
|
||||
/* Enable YCBCR->RGB CSC1 */
|
||||
_init_csc(ipu, IC_TASK_POST_PROCESSOR, YCbCr, RGB, 1);
|
||||
ic_conf |= IC_CONF_PP_CSC1;
|
||||
} else {
|
||||
/* TODO: Support YUV<->YCbCr conversion? */
|
||||
}
|
||||
}
|
||||
|
||||
if (params->mem_pp_mem.graphics_combine_en) {
|
||||
ic_conf |= IC_CONF_PP_CMB;
|
||||
|
||||
if (!(ic_conf & IC_CONF_PP_CSC1)) {
|
||||
/* need transparent CSC1 conversion */
|
||||
_init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, RGB, 1);
|
||||
ic_conf |= IC_CONF_PP_CSC1; /* Enable RGB->RGB CSC */
|
||||
}
|
||||
|
||||
in_fmt = format_to_colorspace(params->mem_pp_mem.in_g_pixel_fmt);
|
||||
out_fmt = format_to_colorspace(params->mem_pp_mem.out_pixel_fmt);
|
||||
if (in_fmt == RGB) {
|
||||
if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
|
||||
/* Enable RGB->YCBCR CSC2 */
|
||||
_init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, out_fmt, 2);
|
||||
ic_conf |= IC_CONF_PP_CSC2;
|
||||
}
|
||||
}
|
||||
if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
|
||||
if (out_fmt == RGB) {
|
||||
/* Enable YCBCR->RGB CSC2 */
|
||||
_init_csc(ipu, IC_TASK_POST_PROCESSOR, YCbCr, RGB, 2);
|
||||
ic_conf |= IC_CONF_PP_CSC2;
|
||||
} else {
|
||||
/* TODO: Support YUV<->YCbCr conversion? */
|
||||
}
|
||||
}
|
||||
|
||||
if (params->mem_pp_mem.global_alpha_en) {
|
||||
ic_conf |= IC_CONF_IC_GLB_LOC_A;
|
||||
reg = ipu_ic_read(ipu, IC_CMBP_1);
|
||||
reg &= ~(0xff00);
|
||||
reg |= (params->mem_pp_mem.alpha << 8);
|
||||
ipu_ic_write(ipu, reg, IC_CMBP_1);
|
||||
} else
|
||||
ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
|
||||
|
||||
if (params->mem_pp_mem.key_color_en) {
|
||||
ic_conf |= IC_CONF_KEY_COLOR_EN;
|
||||
ipu_ic_write(ipu, params->mem_pp_mem.key_color,
|
||||
IC_CMBP_2);
|
||||
} else
|
||||
ic_conf &= ~IC_CONF_KEY_COLOR_EN;
|
||||
} else {
|
||||
ic_conf &= ~IC_CONF_PP_CMB;
|
||||
}
|
||||
|
||||
ipu_ic_write(ipu, ic_conf, IC_CONF);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void _ipu_ic_uninit_pp(struct ipu_soc *ipu)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = ipu_ic_read(ipu, IC_CONF);
|
||||
reg &= ~(IC_CONF_PP_EN | IC_CONF_PP_CSC1 | IC_CONF_PP_CSC2 |
|
||||
IC_CONF_PP_CMB);
|
||||
ipu_ic_write(ipu, reg, IC_CONF);
|
||||
}
|
||||
|
||||
void _ipu_ic_init_rotate_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
|
||||
{
|
||||
}
|
||||
|
||||
void _ipu_ic_uninit_rotate_pp(struct ipu_soc *ipu)
|
||||
{
|
||||
uint32_t reg;
|
||||
reg = ipu_ic_read(ipu, IC_CONF);
|
||||
reg &= ~IC_CONF_PP_ROT_EN;
|
||||
ipu_ic_write(ipu, reg, IC_CONF);
|
||||
}
|
||||
|
||||
int _ipu_ic_idma_init(struct ipu_soc *ipu, int dma_chan,
|
||||
uint16_t width, uint16_t height,
|
||||
int burst_size, ipu_rotate_mode_t rot)
|
||||
{
|
||||
u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
|
||||
u32 temp_rot = bitrev8(rot) >> 5;
|
||||
bool need_hor_flip = false;
|
||||
|
||||
if ((burst_size != 8) && (burst_size != 16)) {
|
||||
dev_dbg(ipu->dev, "Illegal burst length for IC\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
width--;
|
||||
height--;
|
||||
|
||||
if (temp_rot & 0x2) /* Need horizontal flip */
|
||||
need_hor_flip = true;
|
||||
|
||||
ic_idmac_1 = ipu_ic_read(ipu, IC_IDMAC_1);
|
||||
ic_idmac_2 = ipu_ic_read(ipu, IC_IDMAC_2);
|
||||
ic_idmac_3 = ipu_ic_read(ipu, IC_IDMAC_3);
|
||||
if (dma_chan == 22) { /* PP output - CB2 */
|
||||
if (burst_size == 16)
|
||||
ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
|
||||
else
|
||||
ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
|
||||
|
||||
if (need_hor_flip)
|
||||
ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
|
||||
else
|
||||
ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
|
||||
|
||||
ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
|
||||
ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
|
||||
|
||||
ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
|
||||
ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
|
||||
} else if (dma_chan == 11) { /* PP Input - CB5 */
|
||||
if (burst_size == 16)
|
||||
ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
|
||||
else
|
||||
ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
|
||||
} else if (dma_chan == 47) { /* PP Rot input */
|
||||
ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
|
||||
ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
|
||||
}
|
||||
|
||||
if (dma_chan == 12) { /* PRP Input - CB6 */
|
||||
if (burst_size == 16)
|
||||
ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
|
||||
else
|
||||
ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
|
||||
}
|
||||
|
||||
if (dma_chan == 20) { /* PRP ENC output - CB0 */
|
||||
if (burst_size == 16)
|
||||
ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
|
||||
else
|
||||
ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
|
||||
|
||||
if (need_hor_flip)
|
||||
ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
|
||||
else
|
||||
ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
|
||||
|
||||
ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
|
||||
ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
|
||||
|
||||
ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
|
||||
ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
|
||||
|
||||
} else if (dma_chan == 45) { /* PRP ENC Rot input */
|
||||
ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
|
||||
ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
|
||||
}
|
||||
|
||||
if (dma_chan == 21) { /* PRP VF output - CB1 */
|
||||
if (burst_size == 16)
|
||||
ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
|
||||
else
|
||||
ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
|
||||
|
||||
if (need_hor_flip)
|
||||
ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
|
||||
else
|
||||
ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
|
||||
|
||||
ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
|
||||
ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
|
||||
|
||||
ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
|
||||
ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
|
||||
|
||||
} else if (dma_chan == 46) { /* PRP VF Rot input */
|
||||
ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
|
||||
ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
|
||||
}
|
||||
|
||||
if (dma_chan == 14) { /* PRP VF graphics combining input - CB3 */
|
||||
if (burst_size == 16)
|
||||
ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
|
||||
else
|
||||
ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
|
||||
} else if (dma_chan == 15) { /* PP graphics combining input - CB4 */
|
||||
if (burst_size == 16)
|
||||
ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
|
||||
else
|
||||
ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
|
||||
} else if (dma_chan == 5) { /* VDIC OUTPUT - CB7 */
|
||||
if (burst_size == 16)
|
||||
ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
|
||||
else
|
||||
ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
|
||||
}
|
||||
|
||||
ipu_ic_write(ipu, ic_idmac_1, IC_IDMAC_1);
|
||||
ipu_ic_write(ipu, ic_idmac_2, IC_IDMAC_2);
|
||||
ipu_ic_write(ipu, ic_idmac_3, IC_IDMAC_3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _init_csc(struct ipu_soc *ipu, uint8_t ic_task, ipu_color_space_t in_format,
|
||||
ipu_color_space_t out_format, int csc_index)
|
||||
{
|
||||
/*
|
||||
* Y = 0.257 * R + 0.504 * G + 0.098 * B + 16;
|
||||
* U = -0.148 * R - 0.291 * G + 0.439 * B + 128;
|
||||
* V = 0.439 * R - 0.368 * G - 0.071 * B + 128;
|
||||
*/
|
||||
static const uint32_t rgb2ycbcr_coeff[4][3] = {
|
||||
{0x0042, 0x0081, 0x0019},
|
||||
{0x01DA, 0x01B6, 0x0070},
|
||||
{0x0070, 0x01A2, 0x01EE},
|
||||
{0x0040, 0x0200, 0x0200}, /* A0, A1, A2 */
|
||||
};
|
||||
|
||||
/* transparent RGB->RGB matrix for combining
|
||||
*/
|
||||
static const uint32_t rgb2rgb_coeff[4][3] = {
|
||||
{0x0080, 0x0000, 0x0000},
|
||||
{0x0000, 0x0080, 0x0000},
|
||||
{0x0000, 0x0000, 0x0080},
|
||||
{0x0000, 0x0000, 0x0000}, /* A0, A1, A2 */
|
||||
};
|
||||
|
||||
/* R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
|
||||
G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
|
||||
B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); */
|
||||
static const uint32_t ycbcr2rgb_coeff[4][3] = {
|
||||
{149, 0, 204},
|
||||
{149, 462, 408},
|
||||
{149, 255, 0},
|
||||
{8192 - 446, 266, 8192 - 554}, /* A0, A1, A2 */
|
||||
};
|
||||
|
||||
uint32_t param;
|
||||
uint32_t *base = NULL;
|
||||
|
||||
if (ic_task == IC_TASK_ENCODER) {
|
||||
base = (uint32_t *)ipu->tpmem_base + 0x2008 / 4;
|
||||
} else if (ic_task == IC_TASK_VIEWFINDER) {
|
||||
if (csc_index == 1)
|
||||
base = (uint32_t *)ipu->tpmem_base + 0x4028 / 4;
|
||||
else
|
||||
base = (uint32_t *)ipu->tpmem_base + 0x4040 / 4;
|
||||
} else if (ic_task == IC_TASK_POST_PROCESSOR) {
|
||||
if (csc_index == 1)
|
||||
base = (uint32_t *)ipu->tpmem_base + 0x6060 / 4;
|
||||
else
|
||||
base = (uint32_t *)ipu->tpmem_base + 0x6078 / 4;
|
||||
} else {
|
||||
BUG();
|
||||
}
|
||||
|
||||
if ((in_format == YCbCr) && (out_format == RGB)) {
|
||||
/* Init CSC (YCbCr->RGB) */
|
||||
param = (ycbcr2rgb_coeff[3][0] << 27) |
|
||||
(ycbcr2rgb_coeff[0][0] << 18) |
|
||||
(ycbcr2rgb_coeff[1][1] << 9) | ycbcr2rgb_coeff[2][2];
|
||||
writel(param, base++);
|
||||
/* scale = 2, sat = 0 */
|
||||
param = (ycbcr2rgb_coeff[3][0] >> 5) | (2L << (40 - 32));
|
||||
writel(param, base++);
|
||||
|
||||
param = (ycbcr2rgb_coeff[3][1] << 27) |
|
||||
(ycbcr2rgb_coeff[0][1] << 18) |
|
||||
(ycbcr2rgb_coeff[1][0] << 9) | ycbcr2rgb_coeff[2][0];
|
||||
writel(param, base++);
|
||||
param = (ycbcr2rgb_coeff[3][1] >> 5);
|
||||
writel(param, base++);
|
||||
|
||||
param = (ycbcr2rgb_coeff[3][2] << 27) |
|
||||
(ycbcr2rgb_coeff[0][2] << 18) |
|
||||
(ycbcr2rgb_coeff[1][2] << 9) | ycbcr2rgb_coeff[2][1];
|
||||
writel(param, base++);
|
||||
param = (ycbcr2rgb_coeff[3][2] >> 5);
|
||||
writel(param, base++);
|
||||
} else if ((in_format == RGB) && (out_format == YCbCr)) {
|
||||
/* Init CSC (RGB->YCbCr) */
|
||||
param = (rgb2ycbcr_coeff[3][0] << 27) |
|
||||
(rgb2ycbcr_coeff[0][0] << 18) |
|
||||
(rgb2ycbcr_coeff[1][1] << 9) | rgb2ycbcr_coeff[2][2];
|
||||
writel(param, base++);
|
||||
/* scale = 1, sat = 0 */
|
||||
param = (rgb2ycbcr_coeff[3][0] >> 5) | (1UL << 8);
|
||||
writel(param, base++);
|
||||
|
||||
param = (rgb2ycbcr_coeff[3][1] << 27) |
|
||||
(rgb2ycbcr_coeff[0][1] << 18) |
|
||||
(rgb2ycbcr_coeff[1][0] << 9) | rgb2ycbcr_coeff[2][0];
|
||||
writel(param, base++);
|
||||
param = (rgb2ycbcr_coeff[3][1] >> 5);
|
||||
writel(param, base++);
|
||||
|
||||
param = (rgb2ycbcr_coeff[3][2] << 27) |
|
||||
(rgb2ycbcr_coeff[0][2] << 18) |
|
||||
(rgb2ycbcr_coeff[1][2] << 9) | rgb2ycbcr_coeff[2][1];
|
||||
writel(param, base++);
|
||||
param = (rgb2ycbcr_coeff[3][2] >> 5);
|
||||
writel(param, base++);
|
||||
} else if ((in_format == RGB) && (out_format == RGB)) {
|
||||
/* Init CSC */
|
||||
param =
|
||||
(rgb2rgb_coeff[3][0] << 27) | (rgb2rgb_coeff[0][0] << 18) |
|
||||
(rgb2rgb_coeff[1][1] << 9) | rgb2rgb_coeff[2][2];
|
||||
writel(param, base++);
|
||||
/* scale = 2, sat = 0 */
|
||||
param = (rgb2rgb_coeff[3][0] >> 5) | (2UL << 8);
|
||||
writel(param, base++);
|
||||
|
||||
param =
|
||||
(rgb2rgb_coeff[3][1] << 27) | (rgb2rgb_coeff[0][1] << 18) |
|
||||
(rgb2rgb_coeff[1][0] << 9) | rgb2rgb_coeff[2][0];
|
||||
writel(param, base++);
|
||||
param = (rgb2rgb_coeff[3][1] >> 5);
|
||||
writel(param, base++);
|
||||
|
||||
param =
|
||||
(rgb2rgb_coeff[3][2] << 27) | (rgb2rgb_coeff[0][2] << 18) |
|
||||
(rgb2rgb_coeff[1][2] << 9) | rgb2rgb_coeff[2][1];
|
||||
writel(param, base++);
|
||||
param = (rgb2rgb_coeff[3][2] >> 5);
|
||||
writel(param, base++);
|
||||
} else {
|
||||
dev_err(ipu->dev, "Unsupported color space conversion\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int _calc_resize_coeffs(struct ipu_soc *ipu,
|
||||
uint32_t inSize, uint32_t outSize,
|
||||
uint32_t *resizeCoeff,
|
||||
uint32_t *downsizeCoeff)
|
||||
{
|
||||
uint32_t tempSize;
|
||||
uint32_t tempDownsize;
|
||||
|
||||
if (inSize > 4096) {
|
||||
dev_err(ipu->dev, "IC input size(%d) cannot exceed 4096\n",
|
||||
inSize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (outSize > 1024) {
|
||||
dev_err(ipu->dev, "IC output size(%d) cannot exceed 1024\n",
|
||||
outSize);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((outSize << 3) < inSize) {
|
||||
dev_err(ipu->dev, "IC cannot downsize more than 8:1\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Compute downsizing coefficient */
|
||||
/* Output of downsizing unit cannot be more than 1024 */
|
||||
tempDownsize = 0;
|
||||
tempSize = inSize;
|
||||
while (((tempSize > 1024) || (tempSize >= outSize * 2)) &&
|
||||
(tempDownsize < 2)) {
|
||||
tempSize >>= 1;
|
||||
tempDownsize++;
|
||||
}
|
||||
*downsizeCoeff = tempDownsize;
|
||||
|
||||
/* compute resizing coefficient using the following equation:
|
||||
resizeCoeff = M*(SI -1)/(SO - 1)
|
||||
where M = 2^13, SI - input size, SO - output size */
|
||||
*resizeCoeff = (8192L * (tempSize - 1)) / (outSize - 1);
|
||||
if (*resizeCoeff >= 16384L) {
|
||||
dev_err(ipu->dev, "Overflow on IC resize coefficient.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(ipu->dev, "resizing from %u -> %u pixels, "
|
||||
"downsize=%u, resize=%u.%lu (reg=%u)\n", inSize, outSize,
|
||||
*downsizeCoeff, (*resizeCoeff >= 8192L) ? 1 : 0,
|
||||
((*resizeCoeff & 0x1FFF) * 10000L) / 8192L, *resizeCoeff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _ipu_vdi_toggle_top_field_man(struct ipu_soc *ipu)
|
||||
{
|
||||
uint32_t reg;
|
||||
uint32_t mask_reg;
|
||||
|
||||
reg = ipu_vdi_read(ipu, VDI_C);
|
||||
mask_reg = reg & VDI_C_TOP_FIELD_MAN_1;
|
||||
if (mask_reg == VDI_C_TOP_FIELD_MAN_1)
|
||||
reg &= ~VDI_C_TOP_FIELD_MAN_1;
|
||||
else
|
||||
reg |= VDI_C_TOP_FIELD_MAN_1;
|
||||
|
||||
ipu_vdi_write(ipu, reg, VDI_C);
|
||||
}
|
|
@ -0,0 +1,996 @@
|
|||
/*
|
||||
* Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
#ifndef __INCLUDE_IPU_PARAM_MEM_H__
|
||||
#define __INCLUDE_IPU_PARAM_MEM_H__
|
||||
|
||||
#include <linux/bitrev.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "ipu_prv.h"
|
||||
|
||||
extern u32 *ipu_cpmem_base;
|
||||
|
||||
struct ipu_ch_param_word {
|
||||
uint32_t data[5];
|
||||
uint32_t res[3];
|
||||
};
|
||||
|
||||
struct ipu_ch_param {
|
||||
struct ipu_ch_param_word word[2];
|
||||
};
|
||||
|
||||
#define ipu_ch_param_addr(ipu, ch) (((struct ipu_ch_param *)ipu->cpmem_base) + (ch))
|
||||
|
||||
#define _param_word(base, w) \
|
||||
(((struct ipu_ch_param *)(base))->word[(w)].data)
|
||||
|
||||
#define ipu_ch_param_set_field(base, w, bit, size, v) { \
|
||||
int i = (bit) / 32; \
|
||||
int off = (bit) % 32; \
|
||||
_param_word(base, w)[i] |= (v) << off; \
|
||||
if (((bit)+(size)-1)/32 > i) { \
|
||||
_param_word(base, w)[i + 1] |= (v) >> (off ? (32 - off) : 0); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ipu_ch_param_set_field_io(base, w, bit, size, v) { \
|
||||
int i = (bit) / 32; \
|
||||
int off = (bit) % 32; \
|
||||
unsigned reg_offset; \
|
||||
u32 temp; \
|
||||
reg_offset = sizeof(struct ipu_ch_param_word) * w / 4; \
|
||||
reg_offset += i; \
|
||||
temp = readl((u32 *)base + reg_offset); \
|
||||
temp |= (v) << off; \
|
||||
writel(temp, (u32 *)base + reg_offset); \
|
||||
if (((bit)+(size)-1)/32 > i) { \
|
||||
reg_offset++; \
|
||||
temp = readl((u32 *)base + reg_offset); \
|
||||
temp |= (v) >> (off ? (32 - off) : 0); \
|
||||
writel(temp, (u32 *)base + reg_offset); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ipu_ch_param_mod_field(base, w, bit, size, v) { \
|
||||
int i = (bit) / 32; \
|
||||
int off = (bit) % 32; \
|
||||
u32 mask = (1UL << size) - 1; \
|
||||
u32 temp = _param_word(base, w)[i]; \
|
||||
temp &= ~(mask << off); \
|
||||
_param_word(base, w)[i] = temp | (v) << off; \
|
||||
if (((bit)+(size)-1)/32 > i) { \
|
||||
temp = _param_word(base, w)[i + 1]; \
|
||||
temp &= ~(mask >> (32 - off)); \
|
||||
_param_word(base, w)[i + 1] = \
|
||||
temp | ((v) >> (off ? (32 - off) : 0)); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ipu_ch_param_mod_field_io(base, w, bit, size, v) { \
|
||||
int i = (bit) / 32; \
|
||||
int off = (bit) % 32; \
|
||||
u32 mask = (1UL << size) - 1; \
|
||||
unsigned reg_offset; \
|
||||
u32 temp; \
|
||||
reg_offset = sizeof(struct ipu_ch_param_word) * w / 4; \
|
||||
reg_offset += i; \
|
||||
temp = readl((u32 *)base + reg_offset); \
|
||||
temp &= ~(mask << off); \
|
||||
temp |= (v) << off; \
|
||||
writel(temp, (u32 *)base + reg_offset); \
|
||||
if (((bit)+(size)-1)/32 > i) { \
|
||||
reg_offset++; \
|
||||
temp = readl((u32 *)base + reg_offset); \
|
||||
temp &= ~(mask >> (32 - off)); \
|
||||
temp |= ((v) >> (off ? (32 - off) : 0)); \
|
||||
writel(temp, (u32 *)base + reg_offset); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ipu_ch_param_read_field(base, w, bit, size) ({ \
|
||||
u32 temp2; \
|
||||
int i = (bit) / 32; \
|
||||
int off = (bit) % 32; \
|
||||
u32 mask = (1UL << size) - 1; \
|
||||
u32 temp1 = _param_word(base, w)[i]; \
|
||||
temp1 = mask & (temp1 >> off); \
|
||||
if (((bit)+(size)-1)/32 > i) { \
|
||||
temp2 = _param_word(base, w)[i + 1]; \
|
||||
temp2 &= mask >> (off ? (32 - off) : 0); \
|
||||
temp1 |= temp2 << (off ? (32 - off) : 0); \
|
||||
} \
|
||||
temp1; \
|
||||
})
|
||||
|
||||
#define ipu_ch_param_read_field_io(base, w, bit, size) ({ \
|
||||
u32 temp1, temp2; \
|
||||
int i = (bit) / 32; \
|
||||
int off = (bit) % 32; \
|
||||
u32 mask = (1UL << size) - 1; \
|
||||
unsigned reg_offset; \
|
||||
reg_offset = sizeof(struct ipu_ch_param_word) * w / 4; \
|
||||
reg_offset += i; \
|
||||
temp1 = readl((u32 *)base + reg_offset); \
|
||||
temp1 = mask & (temp1 >> off); \
|
||||
if (((bit)+(size)-1)/32 > i) { \
|
||||
reg_offset++; \
|
||||
temp2 = readl((u32 *)base + reg_offset); \
|
||||
temp2 &= mask >> (off ? (32 - off) : 0); \
|
||||
temp1 |= temp2 << (off ? (32 - off) : 0); \
|
||||
} \
|
||||
temp1; \
|
||||
})
|
||||
|
||||
static inline int __ipu_ch_get_third_buf_cpmem_num(int ch)
|
||||
{
|
||||
switch (ch) {
|
||||
case 8:
|
||||
return 64;
|
||||
case 9:
|
||||
return 65;
|
||||
case 10:
|
||||
return 66;
|
||||
case 13:
|
||||
return 67;
|
||||
case 21:
|
||||
return 68;
|
||||
case 23:
|
||||
return 69;
|
||||
case 27:
|
||||
return 70;
|
||||
case 28:
|
||||
return 71;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void _ipu_ch_params_set_packing(struct ipu_ch_param *p,
|
||||
int red_width, int red_offset,
|
||||
int green_width, int green_offset,
|
||||
int blue_width, int blue_offset,
|
||||
int alpha_width, int alpha_offset)
|
||||
{
|
||||
/* Setup red width and offset */
|
||||
ipu_ch_param_set_field(p, 1, 116, 3, red_width - 1);
|
||||
ipu_ch_param_set_field(p, 1, 128, 5, red_offset);
|
||||
/* Setup green width and offset */
|
||||
ipu_ch_param_set_field(p, 1, 119, 3, green_width - 1);
|
||||
ipu_ch_param_set_field(p, 1, 133, 5, green_offset);
|
||||
/* Setup blue width and offset */
|
||||
ipu_ch_param_set_field(p, 1, 122, 3, blue_width - 1);
|
||||
ipu_ch_param_set_field(p, 1, 138, 5, blue_offset);
|
||||
/* Setup alpha width and offset */
|
||||
ipu_ch_param_set_field(p, 1, 125, 3, alpha_width - 1);
|
||||
ipu_ch_param_set_field(p, 1, 143, 5, alpha_offset);
|
||||
}
|
||||
|
||||
static inline void _ipu_ch_param_dump(struct ipu_soc *ipu, int ch)
|
||||
{
|
||||
struct ipu_ch_param *p = ipu_ch_param_addr(ipu, ch);
|
||||
dev_dbg(ipu->dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", ch,
|
||||
p->word[0].data[0], p->word[0].data[1], p->word[0].data[2],
|
||||
p->word[0].data[3], p->word[0].data[4]);
|
||||
dev_dbg(ipu->dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", ch,
|
||||
p->word[1].data[0], p->word[1].data[1], p->word[1].data[2],
|
||||
p->word[1].data[3], p->word[1].data[4]);
|
||||
dev_dbg(ipu->dev, "PFS 0x%x, ",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 85, 4));
|
||||
dev_dbg(ipu->dev, "BPP 0x%x, ",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 107, 3));
|
||||
dev_dbg(ipu->dev, "NPB 0x%x\n",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7));
|
||||
|
||||
dev_dbg(ipu->dev, "FW %d, ",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 125, 13));
|
||||
dev_dbg(ipu->dev, "FH %d, ",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 138, 12));
|
||||
dev_dbg(ipu->dev, "EBA0 0x%x\n",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 0, 29) << 3);
|
||||
dev_dbg(ipu->dev, "EBA1 0x%x\n",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 29, 29) << 3);
|
||||
dev_dbg(ipu->dev, "Stride %d\n",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14));
|
||||
dev_dbg(ipu->dev, "scan_order %d\n",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1));
|
||||
dev_dbg(ipu->dev, "uv_stride %d\n",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 128, 14));
|
||||
dev_dbg(ipu->dev, "u_offset 0x%x\n",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22) << 3);
|
||||
dev_dbg(ipu->dev, "v_offset 0x%x\n",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22) << 3);
|
||||
|
||||
dev_dbg(ipu->dev, "Width0 %d+1, ",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 116, 3));
|
||||
dev_dbg(ipu->dev, "Width1 %d+1, ",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 119, 3));
|
||||
dev_dbg(ipu->dev, "Width2 %d+1, ",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 122, 3));
|
||||
dev_dbg(ipu->dev, "Width3 %d+1, ",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 125, 3));
|
||||
dev_dbg(ipu->dev, "Offset0 %d, ",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 128, 5));
|
||||
dev_dbg(ipu->dev, "Offset1 %d, ",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 133, 5));
|
||||
dev_dbg(ipu->dev, "Offset2 %d, ",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 138, 5));
|
||||
dev_dbg(ipu->dev, "Offset3 %d\n",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 143, 5));
|
||||
}
|
||||
|
||||
static inline void fill_cpmem(struct ipu_soc *ipu, int ch, struct ipu_ch_param *params)
|
||||
{
|
||||
int i, w;
|
||||
void *addr = ipu_ch_param_addr(ipu, ch);
|
||||
|
||||
/* 2 words, 5 valid data */
|
||||
for (w = 0; w < 2; w++) {
|
||||
for (i = 0; i < 5; i++) {
|
||||
writel(params->word[w].data[i], addr);
|
||||
addr += 4;
|
||||
}
|
||||
addr += 12;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void _ipu_ch_param_init(struct ipu_soc *ipu, int ch,
|
||||
uint32_t pixel_fmt, uint32_t width,
|
||||
uint32_t height, uint32_t stride,
|
||||
uint32_t u, uint32_t v,
|
||||
uint32_t uv_stride, dma_addr_t addr0,
|
||||
dma_addr_t addr1, dma_addr_t addr2)
|
||||
{
|
||||
uint32_t u_offset = 0;
|
||||
uint32_t v_offset = 0;
|
||||
uint32_t bs = 0;
|
||||
int32_t sub_ch = 0;
|
||||
struct ipu_ch_param params;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
ipu_ch_param_set_field(¶ms, 0, 125, 13, width - 1);
|
||||
|
||||
if (((ch == 8) || (ch == 9) || (ch == 10)) && !ipu->vdoa_en) {
|
||||
ipu_ch_param_set_field(¶ms, 0, 138, 12, (height / 2) - 1);
|
||||
ipu_ch_param_set_field(¶ms, 1, 102, 14, (stride * 2) - 1);
|
||||
} else {
|
||||
/* note: for vdoa+vdi- ch8/9/10, always use band mode */
|
||||
ipu_ch_param_set_field(¶ms, 0, 138, 12, height - 1);
|
||||
ipu_ch_param_set_field(¶ms, 1, 102, 14, stride - 1);
|
||||
}
|
||||
|
||||
/* EBA is 8-byte aligned */
|
||||
ipu_ch_param_set_field(¶ms, 1, 0, 29, addr0 >> 3);
|
||||
ipu_ch_param_set_field(¶ms, 1, 29, 29, addr1 >> 3);
|
||||
if (addr0%8)
|
||||
dev_warn(ipu->dev,
|
||||
"IDMAC%d's EBA0 is not 8-byte aligned\n", ch);
|
||||
if (addr1%8)
|
||||
dev_warn(ipu->dev,
|
||||
"IDMAC%d's EBA1 is not 8-byte aligned\n", ch);
|
||||
|
||||
switch (pixel_fmt) {
|
||||
case IPU_PIX_FMT_GENERIC:
|
||||
/*Represents 8-bit Generic data */
|
||||
ipu_ch_param_set_field(¶ms, 0, 107, 3, 5); /* bits/pixel */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 6); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 63); /* burst size */
|
||||
|
||||
break;
|
||||
case IPU_PIX_FMT_GENERIC_16:
|
||||
/* Represents 16-bit generic data */
|
||||
ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 6); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */
|
||||
|
||||
break;
|
||||
case IPU_PIX_FMT_GENERIC_32:
|
||||
/*Represents 32-bit Generic data */
|
||||
break;
|
||||
case IPU_PIX_FMT_RGB565:
|
||||
ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */
|
||||
|
||||
_ipu_ch_params_set_packing(¶ms, 5, 0, 6, 5, 5, 11, 8, 16);
|
||||
break;
|
||||
case IPU_PIX_FMT_BGRA4444:
|
||||
ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */
|
||||
|
||||
_ipu_ch_params_set_packing(¶ms, 4, 4, 4, 8, 4, 12, 4, 0);
|
||||
break;
|
||||
case IPU_PIX_FMT_BGRA5551:
|
||||
ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */
|
||||
|
||||
_ipu_ch_params_set_packing(¶ms, 5, 1, 5, 6, 5, 11, 1, 0);
|
||||
break;
|
||||
case IPU_PIX_FMT_BGR24:
|
||||
ipu_ch_param_set_field(¶ms, 0, 107, 3, 1); /* bits/pixel */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 19); /* burst size */
|
||||
|
||||
_ipu_ch_params_set_packing(¶ms, 8, 0, 8, 8, 8, 16, 8, 24);
|
||||
break;
|
||||
case IPU_PIX_FMT_RGB24:
|
||||
case IPU_PIX_FMT_YUV444:
|
||||
ipu_ch_param_set_field(¶ms, 0, 107, 3, 1); /* bits/pixel */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 19); /* burst size */
|
||||
|
||||
_ipu_ch_params_set_packing(¶ms, 8, 16, 8, 8, 8, 0, 8, 24);
|
||||
break;
|
||||
case IPU_PIX_FMT_VYU444:
|
||||
ipu_ch_param_set_field(¶ms, 0, 107, 3, 1); /* bits/pixel */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 19); /* burst size */
|
||||
|
||||
_ipu_ch_params_set_packing(¶ms, 8, 8, 8, 0, 8, 16, 8, 24);
|
||||
break;
|
||||
case IPU_PIX_FMT_AYUV:
|
||||
ipu_ch_param_set_field(¶ms, 0, 107, 3, 0); /* bits/pixel */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */
|
||||
|
||||
_ipu_ch_params_set_packing(¶ms, 8, 8, 8, 16, 8, 24, 8, 0);
|
||||
break;
|
||||
case IPU_PIX_FMT_BGRA32:
|
||||
case IPU_PIX_FMT_BGR32:
|
||||
ipu_ch_param_set_field(¶ms, 0, 107, 3, 0); /* bits/pixel */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */
|
||||
|
||||
_ipu_ch_params_set_packing(¶ms, 8, 8, 8, 16, 8, 24, 8, 0);
|
||||
break;
|
||||
case IPU_PIX_FMT_RGBA32:
|
||||
case IPU_PIX_FMT_RGB32:
|
||||
ipu_ch_param_set_field(¶ms, 0, 107, 3, 0); /* bits/pixel */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */
|
||||
|
||||
_ipu_ch_params_set_packing(¶ms, 8, 24, 8, 16, 8, 8, 8, 0);
|
||||
break;
|
||||
case IPU_PIX_FMT_ABGR32:
|
||||
ipu_ch_param_set_field(¶ms, 0, 107, 3, 0); /* bits/pixel */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */
|
||||
|
||||
_ipu_ch_params_set_packing(¶ms, 8, 0, 8, 8, 8, 16, 8, 24);
|
||||
break;
|
||||
case IPU_PIX_FMT_UYVY:
|
||||
ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 0xA); /* pix format */
|
||||
if ((ch == 8) || (ch == 9) || (ch == 10)) {
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */
|
||||
} else {
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */
|
||||
}
|
||||
break;
|
||||
case IPU_PIX_FMT_YUYV:
|
||||
ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 0x8); /* pix format */
|
||||
if ((ch == 8) || (ch == 9) || (ch == 10)) {
|
||||
if (ipu->vdoa_en) {
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 31);
|
||||
} else {
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 15);
|
||||
}
|
||||
} else {
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */
|
||||
}
|
||||
break;
|
||||
case IPU_PIX_FMT_YUV420P2:
|
||||
case IPU_PIX_FMT_YUV420P:
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 2); /* pix format */
|
||||
|
||||
if (uv_stride < stride / 2)
|
||||
uv_stride = stride / 2;
|
||||
|
||||
u_offset = stride * height;
|
||||
v_offset = u_offset + (uv_stride * height / 2);
|
||||
if ((ch == 8) || (ch == 9) || (ch == 10)) {
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */
|
||||
uv_stride = uv_stride*2;
|
||||
} else {
|
||||
if (_ipu_is_smfc_chan(ch) &&
|
||||
ipu->smfc_idmac_12bit_3planar_bs_fixup)
|
||||
bs = 15;
|
||||
else
|
||||
bs = 31;
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, bs); /* burst size */
|
||||
}
|
||||
break;
|
||||
case IPU_PIX_FMT_YVU420P:
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 2); /* pix format */
|
||||
|
||||
if (uv_stride < stride / 2)
|
||||
uv_stride = stride / 2;
|
||||
|
||||
v_offset = stride * height;
|
||||
u_offset = v_offset + (uv_stride * height / 2);
|
||||
if ((ch == 8) || (ch == 9) || (ch == 10)) {
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */
|
||||
uv_stride = uv_stride*2;
|
||||
} else {
|
||||
if (_ipu_is_smfc_chan(ch) &&
|
||||
ipu->smfc_idmac_12bit_3planar_bs_fixup)
|
||||
bs = 15;
|
||||
else
|
||||
bs = 31;
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, bs); /* burst size */
|
||||
}
|
||||
break;
|
||||
case IPU_PIX_FMT_YVU422P:
|
||||
/* BPP & pixel format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 1); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */
|
||||
|
||||
if (uv_stride < stride / 2)
|
||||
uv_stride = stride / 2;
|
||||
|
||||
v_offset = (v == 0) ? stride * height : v;
|
||||
u_offset = (u == 0) ? v_offset + v_offset / 2 : u;
|
||||
break;
|
||||
case IPU_PIX_FMT_YUV422P:
|
||||
/* BPP & pixel format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 1); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */
|
||||
|
||||
if (uv_stride < stride / 2)
|
||||
uv_stride = stride / 2;
|
||||
|
||||
u_offset = (u == 0) ? stride * height : u;
|
||||
v_offset = (v == 0) ? u_offset + u_offset / 2 : v;
|
||||
break;
|
||||
case IPU_PIX_FMT_YUV444P:
|
||||
/* BPP & pixel format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 0); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */
|
||||
uv_stride = stride;
|
||||
u_offset = (u == 0) ? stride * height : u;
|
||||
v_offset = (v == 0) ? u_offset * 2 : v;
|
||||
break;
|
||||
case IPU_PIX_FMT_NV16:
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 1); /* pix format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */
|
||||
uv_stride = stride;
|
||||
u_offset = (u == 0) ? stride * height : u;
|
||||
break;
|
||||
case IPU_PIX_FMT_NV12:
|
||||
/* BPP & pixel format */
|
||||
ipu_ch_param_set_field(¶ms, 1, 85, 4, 4); /* pix format */
|
||||
uv_stride = stride;
|
||||
u_offset = (u == 0) ? stride * height : u;
|
||||
if ((ch == 8) || (ch == 9) || (ch == 10)) {
|
||||
if (ipu->vdoa_en) {
|
||||
/* one field buffer, memory width 64bits */
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 63);
|
||||
} else {
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 15);
|
||||
/* top/bottom field in one buffer*/
|
||||
uv_stride = uv_stride*2;
|
||||
}
|
||||
} else {
|
||||
ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(ipu->dev, "mxc ipu: unimplemented pixel format\n");
|
||||
break;
|
||||
}
|
||||
/*set burst size to 16*/
|
||||
|
||||
|
||||
if (uv_stride)
|
||||
ipu_ch_param_set_field(¶ms, 1, 128, 14, uv_stride - 1);
|
||||
|
||||
/* Get the uv offset from user when need cropping */
|
||||
if (u || v) {
|
||||
u_offset = u;
|
||||
v_offset = v;
|
||||
}
|
||||
|
||||
/* UBO and VBO are 22-bit and 8-byte aligned */
|
||||
if (u_offset/8 > 0x3fffff)
|
||||
dev_warn(ipu->dev,
|
||||
"IDMAC%d's U offset exceeds IPU limitation\n", ch);
|
||||
if (v_offset/8 > 0x3fffff)
|
||||
dev_warn(ipu->dev,
|
||||
"IDMAC%d's V offset exceeds IPU limitation\n", ch);
|
||||
if (u_offset%8)
|
||||
dev_warn(ipu->dev,
|
||||
"IDMAC%d's U offset is not 8-byte aligned\n", ch);
|
||||
if (v_offset%8)
|
||||
dev_warn(ipu->dev,
|
||||
"IDMAC%d's V offset is not 8-byte aligned\n", ch);
|
||||
|
||||
ipu_ch_param_set_field(¶ms, 0, 46, 22, u_offset / 8);
|
||||
ipu_ch_param_set_field(¶ms, 0, 68, 22, v_offset / 8);
|
||||
|
||||
dev_dbg(ipu->dev, "initializing idma ch %d @ %p\n", ch, ipu_ch_param_addr(ipu, ch));
|
||||
fill_cpmem(ipu, ch, ¶ms);
|
||||
if (addr2) {
|
||||
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
|
||||
if (sub_ch <= 0)
|
||||
return;
|
||||
|
||||
ipu_ch_param_set_field(¶ms, 1, 0, 29, addr2 >> 3);
|
||||
ipu_ch_param_set_field(¶ms, 1, 29, 29, 0);
|
||||
if (addr2%8)
|
||||
dev_warn(ipu->dev,
|
||||
"IDMAC%d's sub-CPMEM entry%d EBA0 is not "
|
||||
"8-byte aligned\n", ch, sub_ch);
|
||||
|
||||
dev_dbg(ipu->dev, "initializing idma ch %d @ %p sub cpmem\n", ch,
|
||||
ipu_ch_param_addr(ipu, sub_ch));
|
||||
fill_cpmem(ipu, sub_ch, ¶ms);
|
||||
}
|
||||
};
|
||||
|
||||
static inline void _ipu_ch_param_set_burst_size(struct ipu_soc *ipu,
|
||||
uint32_t ch,
|
||||
uint16_t burst_pixels)
|
||||
{
|
||||
int32_t sub_ch = 0;
|
||||
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7,
|
||||
burst_pixels - 1);
|
||||
|
||||
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
|
||||
if (sub_ch <= 0)
|
||||
return;
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 78, 7,
|
||||
burst_pixels - 1);
|
||||
};
|
||||
|
||||
static inline int _ipu_ch_param_get_burst_size(struct ipu_soc *ipu, uint32_t ch)
|
||||
{
|
||||
return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7) + 1;
|
||||
};
|
||||
|
||||
static inline int _ipu_ch_param_get_bpp(struct ipu_soc *ipu, uint32_t ch)
|
||||
{
|
||||
return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 107, 3);
|
||||
};
|
||||
|
||||
static inline void _ipu_ch_param_set_buffer(struct ipu_soc *ipu, uint32_t ch,
|
||||
int bufNum, dma_addr_t phyaddr)
|
||||
{
|
||||
if (bufNum == 2) {
|
||||
ch = __ipu_ch_get_third_buf_cpmem_num(ch);
|
||||
if (ch <= 0)
|
||||
return;
|
||||
bufNum = 0;
|
||||
}
|
||||
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 29 * bufNum, 29,
|
||||
phyaddr / 8);
|
||||
};
|
||||
|
||||
static inline void _ipu_ch_param_set_rotation(struct ipu_soc *ipu, uint32_t ch,
|
||||
ipu_rotate_mode_t rot)
|
||||
{
|
||||
u32 temp_rot = bitrev8(rot) >> 5;
|
||||
int32_t sub_ch = 0;
|
||||
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 119, 3, temp_rot);
|
||||
|
||||
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
|
||||
if (sub_ch <= 0)
|
||||
return;
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 119, 3, temp_rot);
|
||||
};
|
||||
|
||||
static inline void _ipu_ch_param_set_block_mode(struct ipu_soc *ipu, uint32_t ch)
|
||||
{
|
||||
int32_t sub_ch = 0;
|
||||
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 117, 2, 1);
|
||||
|
||||
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
|
||||
if (sub_ch <= 0)
|
||||
return;
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 117, 2, 1);
|
||||
};
|
||||
|
||||
static inline void _ipu_ch_param_set_alpha_use_separate_channel(struct ipu_soc *ipu,
|
||||
uint32_t ch,
|
||||
bool option)
|
||||
{
|
||||
int32_t sub_ch = 0;
|
||||
|
||||
if (option) {
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 89, 1, 1);
|
||||
} else {
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 89, 1, 0);
|
||||
}
|
||||
|
||||
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
|
||||
if (sub_ch <= 0)
|
||||
return;
|
||||
|
||||
if (option) {
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 89, 1, 1);
|
||||
} else {
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 89, 1, 0);
|
||||
}
|
||||
};
|
||||
|
||||
static inline void _ipu_ch_param_set_alpha_condition_read(struct ipu_soc *ipu, uint32_t ch)
|
||||
{
|
||||
int32_t sub_ch = 0;
|
||||
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 149, 1, 1);
|
||||
|
||||
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
|
||||
if (sub_ch <= 0)
|
||||
return;
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 149, 1, 1);
|
||||
};
|
||||
|
||||
static inline void _ipu_ch_param_set_alpha_buffer_memory(struct ipu_soc *ipu, uint32_t ch)
|
||||
{
|
||||
int alp_mem_idx;
|
||||
int32_t sub_ch = 0;
|
||||
|
||||
switch (ch) {
|
||||
case 14: /* PRP graphic */
|
||||
alp_mem_idx = 0;
|
||||
break;
|
||||
case 15: /* PP graphic */
|
||||
alp_mem_idx = 1;
|
||||
break;
|
||||
case 23: /* DP BG SYNC graphic */
|
||||
alp_mem_idx = 4;
|
||||
break;
|
||||
case 27: /* DP FG SYNC graphic */
|
||||
alp_mem_idx = 2;
|
||||
break;
|
||||
default:
|
||||
dev_err(ipu->dev, "unsupported correlative channel of local "
|
||||
"alpha channel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 90, 3, alp_mem_idx);
|
||||
|
||||
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
|
||||
if (sub_ch <= 0)
|
||||
return;
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 90, 3, alp_mem_idx);
|
||||
};
|
||||
|
||||
static inline void _ipu_ch_param_set_interlaced_scan(struct ipu_soc *ipu, uint32_t ch)
|
||||
{
|
||||
u32 stride;
|
||||
int32_t sub_ch = 0;
|
||||
|
||||
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
|
||||
|
||||
ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1, 1);
|
||||
if (sub_ch > 0)
|
||||
ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 113, 1, 1);
|
||||
stride = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14) + 1;
|
||||
/* ILO is 20-bit and 8-byte aligned */
|
||||
if (stride/8 > 0xfffff)
|
||||
dev_warn(ipu->dev,
|
||||
"IDMAC%d's ILO exceeds IPU limitation\n", ch);
|
||||
if (stride%8)
|
||||
dev_warn(ipu->dev,
|
||||
"IDMAC%d's ILO is not 8-byte aligned\n", ch);
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 58, 20, stride / 8);
|
||||
if (sub_ch > 0)
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 58, 20,
|
||||
stride / 8);
|
||||
stride *= 2;
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14, stride - 1);
|
||||
if (sub_ch > 0)
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 102, 14,
|
||||
stride - 1);
|
||||
};
|
||||
|
||||
static inline void _ipu_ch_param_set_axi_id(struct ipu_soc *ipu, uint32_t ch, uint32_t id)
|
||||
{
|
||||
int32_t sub_ch = 0;
|
||||
|
||||
id %= 4;
|
||||
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 93, 2, id);
|
||||
|
||||
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
|
||||
if (sub_ch <= 0)
|
||||
return;
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 93, 2, id);
|
||||
};
|
||||
|
||||
static inline int _ipu_ch_param_get_axi_id(struct ipu_soc *ipu, uint32_t ch)
|
||||
{
|
||||
return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 93, 2);
|
||||
}
|
||||
|
||||
static inline int __ipu_ch_offset_calc(uint32_t pixel_fmt,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t stride,
|
||||
uint32_t u,
|
||||
uint32_t v,
|
||||
uint32_t uv_stride,
|
||||
uint32_t vertical_offset,
|
||||
uint32_t horizontal_offset,
|
||||
uint32_t *u_offset,
|
||||
uint32_t *v_offset)
|
||||
{
|
||||
uint32_t u_fix = 0;
|
||||
uint32_t v_fix = 0;
|
||||
|
||||
switch (pixel_fmt) {
|
||||
case IPU_PIX_FMT_GENERIC:
|
||||
case IPU_PIX_FMT_GENERIC_16:
|
||||
case IPU_PIX_FMT_GENERIC_32:
|
||||
case IPU_PIX_FMT_RGB565:
|
||||
case IPU_PIX_FMT_BGR24:
|
||||
case IPU_PIX_FMT_RGB24:
|
||||
case IPU_PIX_FMT_YUV444:
|
||||
case IPU_PIX_FMT_BGRA32:
|
||||
case IPU_PIX_FMT_BGR32:
|
||||
case IPU_PIX_FMT_RGBA32:
|
||||
case IPU_PIX_FMT_RGB32:
|
||||
case IPU_PIX_FMT_ABGR32:
|
||||
case IPU_PIX_FMT_UYVY:
|
||||
case IPU_PIX_FMT_YUYV:
|
||||
case IPU_PIX_FMT_GPU32_SB_ST:
|
||||
case IPU_PIX_FMT_GPU32_SB_SRT:
|
||||
case IPU_PIX_FMT_GPU32_ST:
|
||||
case IPU_PIX_FMT_GPU32_SRT:
|
||||
case IPU_PIX_FMT_GPU16_SB_ST:
|
||||
case IPU_PIX_FMT_GPU16_SB_SRT:
|
||||
case IPU_PIX_FMT_GPU16_ST:
|
||||
case IPU_PIX_FMT_GPU16_SRT:
|
||||
*u_offset = 0;
|
||||
*v_offset = 0;
|
||||
break;
|
||||
case IPU_PIX_FMT_YUV420P2:
|
||||
case IPU_PIX_FMT_YUV420P:
|
||||
if (uv_stride < stride / 2)
|
||||
uv_stride = stride / 2;
|
||||
|
||||
*u_offset = stride * (height - vertical_offset - 1) +
|
||||
(stride - horizontal_offset) +
|
||||
(uv_stride * vertical_offset / 2) +
|
||||
horizontal_offset / 2;
|
||||
*v_offset = *u_offset + (uv_stride * height / 2);
|
||||
u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
|
||||
(horizontal_offset / 2) -
|
||||
(stride * vertical_offset) - (horizontal_offset)) :
|
||||
*u_offset;
|
||||
v_fix = v ? (v + (uv_stride * vertical_offset / 2) +
|
||||
(horizontal_offset / 2) -
|
||||
(stride * vertical_offset) - (horizontal_offset)) :
|
||||
*v_offset;
|
||||
break;
|
||||
case IPU_PIX_FMT_YVU420P:
|
||||
if (uv_stride < stride / 2)
|
||||
uv_stride = stride / 2;
|
||||
|
||||
*v_offset = stride * (height - vertical_offset - 1) +
|
||||
(stride - horizontal_offset) +
|
||||
(uv_stride * vertical_offset / 2) +
|
||||
horizontal_offset / 2;
|
||||
*u_offset = *v_offset + (uv_stride * height / 2);
|
||||
u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
|
||||
(horizontal_offset / 2) -
|
||||
(stride * vertical_offset) - (horizontal_offset)) :
|
||||
*u_offset;
|
||||
v_fix = v ? (v + (uv_stride * vertical_offset / 2) +
|
||||
(horizontal_offset / 2) -
|
||||
(stride * vertical_offset) - (horizontal_offset)) :
|
||||
*v_offset;
|
||||
break;
|
||||
case IPU_PIX_FMT_YVU422P:
|
||||
if (uv_stride < stride / 2)
|
||||
uv_stride = stride / 2;
|
||||
|
||||
*v_offset = stride * (height - vertical_offset - 1) +
|
||||
(stride - horizontal_offset) +
|
||||
(uv_stride * vertical_offset) +
|
||||
horizontal_offset / 2;
|
||||
*u_offset = *v_offset + uv_stride * height;
|
||||
u_fix = u ? (u + (uv_stride * vertical_offset) +
|
||||
horizontal_offset / 2 -
|
||||
(stride * vertical_offset) - (horizontal_offset)) :
|
||||
*u_offset;
|
||||
v_fix = v ? (v + (uv_stride * vertical_offset) +
|
||||
horizontal_offset / 2 -
|
||||
(stride * vertical_offset) - (horizontal_offset)) :
|
||||
*v_offset;
|
||||
break;
|
||||
case IPU_PIX_FMT_YUV422P:
|
||||
if (uv_stride < stride / 2)
|
||||
uv_stride = stride / 2;
|
||||
|
||||
*u_offset = stride * (height - vertical_offset - 1) +
|
||||
(stride - horizontal_offset) +
|
||||
(uv_stride * vertical_offset) +
|
||||
horizontal_offset / 2;
|
||||
*v_offset = *u_offset + uv_stride * height;
|
||||
u_fix = u ? (u + (uv_stride * vertical_offset) +
|
||||
horizontal_offset / 2 -
|
||||
(stride * vertical_offset) - (horizontal_offset)) :
|
||||
*u_offset;
|
||||
v_fix = v ? (v + (uv_stride * vertical_offset) +
|
||||
horizontal_offset / 2 -
|
||||
(stride * vertical_offset) - (horizontal_offset)) :
|
||||
*v_offset;
|
||||
break;
|
||||
case IPU_PIX_FMT_YUV444P:
|
||||
uv_stride = stride;
|
||||
*u_offset = stride * (height - vertical_offset - 1) +
|
||||
(stride - horizontal_offset) +
|
||||
(uv_stride * vertical_offset) +
|
||||
horizontal_offset;
|
||||
*v_offset = *u_offset + uv_stride * height;
|
||||
u_fix = u ? (u + (uv_stride * vertical_offset) +
|
||||
horizontal_offset -
|
||||
(stride * vertical_offset) -
|
||||
(horizontal_offset)) :
|
||||
*u_offset;
|
||||
v_fix = v ? (v + (uv_stride * vertical_offset) +
|
||||
horizontal_offset -
|
||||
(stride * vertical_offset) -
|
||||
(horizontal_offset)) :
|
||||
*v_offset;
|
||||
break;
|
||||
case IPU_PIX_FMT_NV12:
|
||||
case IPU_PIX_FMT_NV16:
|
||||
case PRE_PIX_FMT_NV21:
|
||||
case PRE_PIX_FMT_NV61:
|
||||
uv_stride = stride;
|
||||
*u_offset = stride * (height - vertical_offset - 1) +
|
||||
(stride - horizontal_offset) +
|
||||
(uv_stride * vertical_offset / 2) +
|
||||
horizontal_offset;
|
||||
*v_offset = 0;
|
||||
u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
|
||||
horizontal_offset -
|
||||
(stride * vertical_offset) - (horizontal_offset)) :
|
||||
*u_offset;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (u_fix > *u_offset)
|
||||
*u_offset = u_fix;
|
||||
|
||||
if (v_fix > *v_offset)
|
||||
*v_offset = v_fix;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* IDMAC U/V offset changing support */
|
||||
/* U and V input is not affected, */
|
||||
/* the update is done by new calculation according to */
|
||||
/* vertical_offset and horizontal_offset */
|
||||
static inline void _ipu_ch_offset_update(struct ipu_soc *ipu,
|
||||
int ch,
|
||||
uint32_t pixel_fmt,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t stride,
|
||||
uint32_t u,
|
||||
uint32_t v,
|
||||
uint32_t uv_stride,
|
||||
uint32_t vertical_offset,
|
||||
uint32_t horizontal_offset)
|
||||
{
|
||||
uint32_t u_offset = 0;
|
||||
uint32_t v_offset = 0;
|
||||
uint32_t old_offset = 0;
|
||||
int32_t sub_ch = 0;
|
||||
int ret;
|
||||
|
||||
ret = __ipu_ch_offset_calc(pixel_fmt, width, height, stride,
|
||||
u, v, uv_stride,
|
||||
vertical_offset, horizontal_offset,
|
||||
&u_offset, &v_offset);
|
||||
if (ret) {
|
||||
dev_err(ipu->dev, "mxc ipu: unimplemented pixel format\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* UBO and VBO are 22-bit and 8-byte aligned */
|
||||
if (u_offset/8 > 0x3fffff)
|
||||
dev_warn(ipu->dev,
|
||||
"IDMAC%d's U offset exceeds IPU limitation\n", ch);
|
||||
if (v_offset/8 > 0x3fffff)
|
||||
dev_warn(ipu->dev,
|
||||
"IDMAC%d's V offset exceeds IPU limitation\n", ch);
|
||||
if (u_offset%8)
|
||||
dev_warn(ipu->dev,
|
||||
"IDMAC%d's U offset is not 8-byte aligned\n", ch);
|
||||
if (v_offset%8)
|
||||
dev_warn(ipu->dev,
|
||||
"IDMAC%d's V offset is not 8-byte aligned\n", ch);
|
||||
|
||||
old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22);
|
||||
if (old_offset != u_offset / 8)
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22, u_offset / 8);
|
||||
old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22);
|
||||
if (old_offset != v_offset / 8)
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22, v_offset / 8);
|
||||
|
||||
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
|
||||
if (sub_ch <= 0)
|
||||
return;
|
||||
old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22);
|
||||
if (old_offset != u_offset / 8)
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22, u_offset / 8);
|
||||
old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22);
|
||||
if (old_offset != v_offset / 8)
|
||||
ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22, v_offset / 8);
|
||||
};
|
||||
|
||||
static inline void _ipu_ch_params_set_alpha_width(struct ipu_soc *ipu, uint32_t ch, int alpha_width)
|
||||
{
|
||||
int32_t sub_ch = 0;
|
||||
|
||||
ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 1, 125, 3, alpha_width - 1);
|
||||
|
||||
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
|
||||
if (sub_ch <= 0)
|
||||
return;
|
||||
ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 125, 3, alpha_width - 1);
|
||||
};
|
||||
|
||||
static inline void _ipu_ch_param_set_bandmode(struct ipu_soc *ipu,
|
||||
uint32_t ch, uint32_t band_height)
|
||||
{
|
||||
int32_t sub_ch = 0;
|
||||
|
||||
ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch),
|
||||
0, 114, 3, band_height - 1);
|
||||
sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
|
||||
if (sub_ch <= 0)
|
||||
return;
|
||||
ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch),
|
||||
0, 114, 3, band_height - 1);
|
||||
|
||||
dev_dbg(ipu->dev, "BNDM 0x%x, ",
|
||||
ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 114, 3));
|
||||
}
|
||||
|
||||
/*
|
||||
* The IPUv3 IDMAC has a bug to read 32bpp pixels from a graphics plane
|
||||
* whose alpha component is at the most significant 8 bits. The bug only
|
||||
* impacts on cases in which the relevant separate alpha channel is enabled.
|
||||
*
|
||||
* Return true on bad alpha component position, otherwise, return false.
|
||||
*/
|
||||
static inline bool _ipu_ch_param_bad_alpha_pos(uint32_t pixel_fmt)
|
||||
{
|
||||
switch (pixel_fmt) {
|
||||
case IPU_PIX_FMT_BGRA32:
|
||||
case IPU_PIX_FMT_BGR32:
|
||||
case IPU_PIX_FMT_RGBA32:
|
||||
case IPU_PIX_FMT_RGB32:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file ipu_pixel_clk.c
|
||||
*
|
||||
* @brief IPU pixel clock implementation
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ipu-v3.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "ipu_prv.h"
|
||||
#include "ipu_regs.h"
|
||||
|
||||
/*
|
||||
* muxd clock implementation
|
||||
*/
|
||||
struct clk_di_mux {
|
||||
struct clk_hw hw;
|
||||
u8 ipu_id;
|
||||
u8 di_id;
|
||||
u8 flags;
|
||||
u8 index;
|
||||
};
|
||||
#define to_clk_di_mux(_hw) container_of(_hw, struct clk_di_mux, hw)
|
||||
|
||||
static int _ipu_pixel_clk_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_di_mux *mux = to_clk_di_mux(hw);
|
||||
struct ipu_soc *ipu = ipu_get_soc(mux->ipu_id);
|
||||
u32 di_gen;
|
||||
|
||||
di_gen = ipu_di_read(ipu, mux->di_id, DI_GENERAL);
|
||||
if (index == 0)
|
||||
/* ipu1_clk or ipu2_clk internal clk */
|
||||
di_gen &= ~DI_GEN_DI_CLK_EXT;
|
||||
else
|
||||
di_gen |= DI_GEN_DI_CLK_EXT;
|
||||
|
||||
ipu_di_write(ipu, mux->di_id, di_gen, DI_GENERAL);
|
||||
mux->index = index;
|
||||
pr_debug("ipu_pixel_clk: di_clk_ext:0x%x, di_gen reg:0x%x.\n",
|
||||
!(di_gen & DI_GEN_DI_CLK_EXT), di_gen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 _ipu_pixel_clk_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_di_mux *mux = to_clk_di_mux(hw);
|
||||
|
||||
return mux->index;
|
||||
}
|
||||
|
||||
const struct clk_ops clk_mux_di_ops = {
|
||||
.get_parent = _ipu_pixel_clk_get_parent,
|
||||
.set_parent = _ipu_pixel_clk_set_parent,
|
||||
};
|
||||
|
||||
struct clk *clk_register_mux_pix_clk(struct device *dev, const char *name,
|
||||
const char **parent_names, u8 num_parents, unsigned long flags,
|
||||
u8 ipu_id, u8 di_id, u8 clk_mux_flags)
|
||||
{
|
||||
struct clk_di_mux *mux;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
mux = kzalloc(sizeof(struct clk_di_mux), GFP_KERNEL);
|
||||
if (!mux)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_mux_di_ops;
|
||||
init.flags = flags;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
|
||||
mux->ipu_id = ipu_id;
|
||||
mux->di_id = di_id;
|
||||
mux->flags = clk_mux_flags | CLK_SET_RATE_PARENT;
|
||||
mux->hw.init = &init;
|
||||
|
||||
clk = clk_register(dev, &mux->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(mux);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gated clock implementation
|
||||
*/
|
||||
struct clk_di_div {
|
||||
struct clk_hw hw;
|
||||
u8 ipu_id;
|
||||
u8 di_id;
|
||||
u8 flags;
|
||||
};
|
||||
#define to_clk_di_div(_hw) container_of(_hw, struct clk_di_div, hw)
|
||||
|
||||
static unsigned long _ipu_pixel_clk_div_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_di_div *di_div = to_clk_di_div(hw);
|
||||
struct ipu_soc *ipu = ipu_get_soc(di_div->ipu_id);
|
||||
u32 div;
|
||||
u64 final_rate = (unsigned long long)parent_rate * 16;
|
||||
|
||||
_ipu_get(ipu);
|
||||
div = ipu_di_read(ipu, di_div->di_id, DI_BS_CLKGEN0);
|
||||
_ipu_put(ipu);
|
||||
pr_debug("ipu_di%d read BS_CLKGEN0 div:%d, final_rate:%lld, prate:%ld\n",
|
||||
di_div->di_id, div, final_rate, parent_rate);
|
||||
|
||||
if (div == 0)
|
||||
return 0;
|
||||
do_div(final_rate, div);
|
||||
|
||||
return (unsigned long)final_rate;
|
||||
}
|
||||
|
||||
static long _ipu_pixel_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_clk_rate)
|
||||
{
|
||||
u64 div, final_rate;
|
||||
u32 remainder;
|
||||
u64 parent_rate = (unsigned long long)(*parent_clk_rate) * 16;
|
||||
|
||||
/*
|
||||
* Calculate divider
|
||||
* Fractional part is 4 bits,
|
||||
* so simply multiply by 2^4 to get fractional part.
|
||||
*/
|
||||
div = parent_rate;
|
||||
remainder = do_div(div, rate);
|
||||
/* Round the divider value */
|
||||
if (remainder > (rate/2))
|
||||
div++;
|
||||
if (div < 0x10) /* Min DI disp clock divider is 1 */
|
||||
div = 0x10;
|
||||
if (div & ~0xFEF)
|
||||
div &= 0xFF8;
|
||||
else {
|
||||
/* Round up divider if it gets us closer to desired pix clk */
|
||||
if ((div & 0xC) == 0xC) {
|
||||
div += 0x10;
|
||||
div &= ~0xF;
|
||||
}
|
||||
}
|
||||
final_rate = parent_rate;
|
||||
do_div(final_rate, div);
|
||||
|
||||
return final_rate;
|
||||
}
|
||||
|
||||
static int _ipu_pixel_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_clk_rate)
|
||||
{
|
||||
struct clk_di_div *di_div = to_clk_di_div(hw);
|
||||
struct ipu_soc *ipu = ipu_get_soc(di_div->ipu_id);
|
||||
u64 div, parent_rate;
|
||||
u32 remainder;
|
||||
|
||||
parent_rate = (unsigned long long)parent_clk_rate * 16;
|
||||
div = parent_rate;
|
||||
remainder = do_div(div, rate);
|
||||
/* Round the divider value */
|
||||
if (remainder > (rate/2))
|
||||
div++;
|
||||
|
||||
/* Round up divider if it gets us closer to desired pix clk */
|
||||
if ((div & 0xC) == 0xC) {
|
||||
div += 0x10;
|
||||
div &= ~0xF;
|
||||
}
|
||||
if (div > 0x1000)
|
||||
pr_err("Overflow, di:%d, DI_BS_CLKGEN0 div:0x%x\n",
|
||||
di_div->di_id, (u32)div);
|
||||
_ipu_get(ipu);
|
||||
ipu_di_write(ipu, di_div->di_id, (u32)div, DI_BS_CLKGEN0);
|
||||
|
||||
/* Setup pixel clock timing */
|
||||
/* FIXME: needs to be more flexible */
|
||||
/* Down time is half of period */
|
||||
ipu_di_write(ipu, di_div->di_id, ((u32)div / 16) << 16, DI_BS_CLKGEN1);
|
||||
_ipu_put(ipu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_ops clk_div_ops = {
|
||||
.recalc_rate = _ipu_pixel_clk_div_recalc_rate,
|
||||
.round_rate = _ipu_pixel_clk_div_round_rate,
|
||||
.set_rate = _ipu_pixel_clk_div_set_rate,
|
||||
};
|
||||
|
||||
struct clk *clk_register_div_pix_clk(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
u8 ipu_id, u8 di_id, u8 clk_div_flags)
|
||||
{
|
||||
struct clk_di_div *di_div;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
di_div = kzalloc(sizeof(struct clk_di_div), GFP_KERNEL);
|
||||
if (!di_div)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* struct clk_di_div assignments */
|
||||
di_div->ipu_id = ipu_id;
|
||||
di_div->di_id = di_id;
|
||||
di_div->flags = clk_div_flags;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_div_ops;
|
||||
init.flags = flags | CLK_SET_RATE_PARENT;
|
||||
init.parent_names = parent_name ? &parent_name : NULL;
|
||||
init.num_parents = parent_name ? 1 : 0;
|
||||
|
||||
di_div->hw.init = &init;
|
||||
|
||||
clk = clk_register(dev, &di_div->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(clk);
|
||||
|
||||
return clk;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gated clock implementation
|
||||
*/
|
||||
struct clk_di_gate {
|
||||
struct clk_hw hw;
|
||||
u8 ipu_id;
|
||||
u8 di_id;
|
||||
u8 flags;
|
||||
};
|
||||
#define to_clk_di_gate(_hw) container_of(_hw, struct clk_di_gate, hw)
|
||||
|
||||
static int _ipu_pixel_clk_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_di_gate *gate = to_clk_di_gate(hw);
|
||||
struct ipu_soc *ipu = ipu_get_soc(gate->ipu_id);
|
||||
u32 disp_gen;
|
||||
|
||||
disp_gen = ipu_cm_read(ipu, IPU_DISP_GEN);
|
||||
disp_gen |= gate->di_id ? DI1_COUNTER_RELEASE : DI0_COUNTER_RELEASE;
|
||||
ipu_cm_write(ipu, disp_gen, IPU_DISP_GEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _ipu_pixel_clk_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_di_gate *gate = to_clk_di_gate(hw);
|
||||
struct ipu_soc *ipu = ipu_get_soc(gate->ipu_id);
|
||||
u32 disp_gen;
|
||||
|
||||
disp_gen = ipu_cm_read(ipu, IPU_DISP_GEN);
|
||||
disp_gen &= gate->di_id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE;
|
||||
ipu_cm_write(ipu, disp_gen, IPU_DISP_GEN);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static struct clk_ops clk_gate_di_ops = {
|
||||
.enable = _ipu_pixel_clk_enable,
|
||||
.disable = _ipu_pixel_clk_disable,
|
||||
};
|
||||
|
||||
struct clk *clk_register_gate_pix_clk(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
u8 ipu_id, u8 di_id, u8 clk_gate_flags)
|
||||
{
|
||||
struct clk_di_gate *gate;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
gate = kzalloc(sizeof(struct clk_di_gate), GFP_KERNEL);
|
||||
if (!gate)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
gate->ipu_id = ipu_id;
|
||||
gate->di_id = di_id;
|
||||
gate->flags = clk_gate_flags;
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_gate_di_ops;
|
||||
init.flags = flags | CLK_SET_RATE_PARENT;
|
||||
init.parent_names = parent_name ? &parent_name : NULL;
|
||||
init.num_parents = parent_name ? 1 : 0;
|
||||
|
||||
gate->hw.init = &init;
|
||||
|
||||
clk = clk_register(dev, &gate->hw);
|
||||
if (IS_ERR(clk))
|
||||
kfree(clk);
|
||||
|
||||
return clk;
|
||||
}
|
|
@ -0,0 +1,368 @@
|
|||
/*
|
||||
* Copyright 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
#ifndef __INCLUDE_IPU_PRV_H__
|
||||
#define __INCLUDE_IPU_PRV_H__
|
||||
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fsl_devices.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define MXC_IPU_MAX_NUM 2
|
||||
#define MXC_DI_NUM_PER_IPU 2
|
||||
|
||||
/* Globals */
|
||||
extern int dmfc_type_setup;
|
||||
|
||||
#define IDMA_CHAN_INVALID 0xFF
|
||||
#define HIGH_RESOLUTION_WIDTH 1024
|
||||
|
||||
enum ipuv3_type {
|
||||
IPUv3D, /* i.MX37 */
|
||||
IPUv3EX, /* i.MX51 */
|
||||
IPUv3M, /* i.MX53 */
|
||||
IPUv3H, /* i.MX6Q/SDL */
|
||||
};
|
||||
|
||||
#define IPU_MAX_VDI_IN_WIDTH(type) ({ (type) >= IPUv3M ? 968 : 720; })
|
||||
|
||||
struct ipu_irq_node {
|
||||
irqreturn_t(*handler) (int, void *); /*!< the ISR */
|
||||
const char *name; /*!< device associated with the interrupt */
|
||||
void *dev_id; /*!< some unique information for the ISR */
|
||||
__u32 flags; /*!< not used */
|
||||
};
|
||||
|
||||
enum csc_type_t {
|
||||
RGB2YUV = 0,
|
||||
YUV2RGB,
|
||||
RGB2RGB,
|
||||
YUV2YUV,
|
||||
CSC_NONE,
|
||||
CSC_NUM
|
||||
};
|
||||
|
||||
struct ipu_soc {
|
||||
unsigned int id;
|
||||
unsigned int devtype;
|
||||
bool online;
|
||||
|
||||
/*clk*/
|
||||
struct clk *ipu_clk;
|
||||
struct clk *di_clk[2];
|
||||
struct clk *di_clk_sel[2];
|
||||
struct clk *pixel_clk[2];
|
||||
bool pixel_clk_en[2];
|
||||
struct clk *pixel_clk_sel[2];
|
||||
struct clk *csi_clk[2];
|
||||
struct clk *prg_clk;
|
||||
|
||||
/*irq*/
|
||||
int irq_sync;
|
||||
int irq_err;
|
||||
struct ipu_irq_node irq_list[IPU_IRQ_COUNT];
|
||||
|
||||
/*reg*/
|
||||
void __iomem *cm_reg;
|
||||
void __iomem *idmac_reg;
|
||||
void __iomem *dp_reg;
|
||||
void __iomem *ic_reg;
|
||||
void __iomem *dc_reg;
|
||||
void __iomem *dc_tmpl_reg;
|
||||
void __iomem *dmfc_reg;
|
||||
void __iomem *di_reg[2];
|
||||
void __iomem *smfc_reg;
|
||||
void __iomem *csi_reg[2];
|
||||
void __iomem *cpmem_base;
|
||||
void __iomem *tpmem_base;
|
||||
void __iomem *vdi_reg;
|
||||
|
||||
struct device *dev;
|
||||
|
||||
ipu_channel_t csi_channel[2];
|
||||
ipu_channel_t using_ic_dirct_ch;
|
||||
unsigned char dc_di_assignment[10];
|
||||
bool sec_chan_en[24];
|
||||
bool thrd_chan_en[24];
|
||||
bool chan_is_interlaced[52];
|
||||
uint32_t channel_init_mask;
|
||||
uint32_t channel_enable_mask;
|
||||
|
||||
/*use count*/
|
||||
int dc_use_count;
|
||||
int dp_use_count;
|
||||
int dmfc_use_count;
|
||||
int smfc_use_count;
|
||||
int ic_use_count;
|
||||
int rot_use_count;
|
||||
int vdi_use_count;
|
||||
int di_use_count[2];
|
||||
int csi_use_count[2];
|
||||
|
||||
struct mutex mutex_lock;
|
||||
spinlock_t int_reg_spin_lock;
|
||||
spinlock_t rdy_reg_spin_lock;
|
||||
|
||||
int dmfc_size_28;
|
||||
int dmfc_size_29;
|
||||
int dmfc_size_24;
|
||||
int dmfc_size_27;
|
||||
int dmfc_size_23;
|
||||
|
||||
enum csc_type_t fg_csc_type;
|
||||
enum csc_type_t bg_csc_type;
|
||||
bool color_key_4rgb;
|
||||
bool dc_swap;
|
||||
struct completion dc_comp;
|
||||
struct completion csi_comp;
|
||||
|
||||
struct rot_mem {
|
||||
void *vaddr;
|
||||
dma_addr_t paddr;
|
||||
int size;
|
||||
} rot_dma[2];
|
||||
|
||||
int vdoa_en;
|
||||
struct task_struct *thread[2];
|
||||
|
||||
/*
|
||||
* Bypass reset to avoid display channel being
|
||||
* stopped by probe since it may starts to work
|
||||
* in bootloader.
|
||||
*/
|
||||
bool bypass_reset;
|
||||
|
||||
unsigned int ch0123_axi;
|
||||
unsigned int ch23_axi;
|
||||
unsigned int ch27_axi;
|
||||
unsigned int ch28_axi;
|
||||
unsigned int normal_axi;
|
||||
|
||||
bool smfc_idmac_12bit_3planar_bs_fixup; /* workaround little stripes */
|
||||
};
|
||||
|
||||
struct ipu_channel {
|
||||
u8 video_in_dma;
|
||||
u8 alpha_in_dma;
|
||||
u8 graph_in_dma;
|
||||
u8 out_dma;
|
||||
};
|
||||
|
||||
enum ipu_dmfc_type {
|
||||
DMFC_NORMAL = 0,
|
||||
DMFC_HIGH_RESOLUTION_DC,
|
||||
DMFC_HIGH_RESOLUTION_DP,
|
||||
DMFC_HIGH_RESOLUTION_ONLY_DP,
|
||||
};
|
||||
|
||||
static inline int _ipu_is_smfc_chan(uint32_t dma_chan)
|
||||
{
|
||||
return ((dma_chan >= 0) && (dma_chan <= 3));
|
||||
}
|
||||
|
||||
static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
|
||||
{
|
||||
return readl(ipu->cm_reg + offset);
|
||||
}
|
||||
|
||||
static inline void ipu_cm_write(struct ipu_soc *ipu,
|
||||
u32 value, unsigned offset)
|
||||
{
|
||||
writel(value, ipu->cm_reg + offset);
|
||||
}
|
||||
|
||||
static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
|
||||
{
|
||||
return readl(ipu->idmac_reg + offset);
|
||||
}
|
||||
|
||||
static inline void ipu_idmac_write(struct ipu_soc *ipu,
|
||||
u32 value, unsigned offset)
|
||||
{
|
||||
writel(value, ipu->idmac_reg + offset);
|
||||
}
|
||||
|
||||
static inline u32 ipu_dc_read(struct ipu_soc *ipu, unsigned offset)
|
||||
{
|
||||
return readl(ipu->dc_reg + offset);
|
||||
}
|
||||
|
||||
static inline void ipu_dc_write(struct ipu_soc *ipu,
|
||||
u32 value, unsigned offset)
|
||||
{
|
||||
writel(value, ipu->dc_reg + offset);
|
||||
}
|
||||
|
||||
static inline u32 ipu_dc_tmpl_read(struct ipu_soc *ipu, unsigned offset)
|
||||
{
|
||||
return readl(ipu->dc_tmpl_reg + offset);
|
||||
}
|
||||
|
||||
static inline void ipu_dc_tmpl_write(struct ipu_soc *ipu,
|
||||
u32 value, unsigned offset)
|
||||
{
|
||||
writel(value, ipu->dc_tmpl_reg + offset);
|
||||
}
|
||||
|
||||
static inline u32 ipu_dmfc_read(struct ipu_soc *ipu, unsigned offset)
|
||||
{
|
||||
return readl(ipu->dmfc_reg + offset);
|
||||
}
|
||||
|
||||
static inline void ipu_dmfc_write(struct ipu_soc *ipu,
|
||||
u32 value, unsigned offset)
|
||||
{
|
||||
writel(value, ipu->dmfc_reg + offset);
|
||||
}
|
||||
|
||||
static inline u32 ipu_dp_read(struct ipu_soc *ipu, unsigned offset)
|
||||
{
|
||||
return readl(ipu->dp_reg + offset);
|
||||
}
|
||||
|
||||
static inline void ipu_dp_write(struct ipu_soc *ipu,
|
||||
u32 value, unsigned offset)
|
||||
{
|
||||
writel(value, ipu->dp_reg + offset);
|
||||
}
|
||||
|
||||
static inline u32 ipu_di_read(struct ipu_soc *ipu, int di, unsigned offset)
|
||||
{
|
||||
return readl(ipu->di_reg[di] + offset);
|
||||
}
|
||||
|
||||
static inline void ipu_di_write(struct ipu_soc *ipu, int di,
|
||||
u32 value, unsigned offset)
|
||||
{
|
||||
writel(value, ipu->di_reg[di] + offset);
|
||||
}
|
||||
|
||||
static inline u32 ipu_csi_read(struct ipu_soc *ipu, int csi, unsigned offset)
|
||||
{
|
||||
return readl(ipu->csi_reg[csi] + offset);
|
||||
}
|
||||
|
||||
static inline void ipu_csi_write(struct ipu_soc *ipu, int csi,
|
||||
u32 value, unsigned offset)
|
||||
{
|
||||
writel(value, ipu->csi_reg[csi] + offset);
|
||||
}
|
||||
|
||||
static inline u32 ipu_smfc_read(struct ipu_soc *ipu, unsigned offset)
|
||||
{
|
||||
return readl(ipu->smfc_reg + offset);
|
||||
}
|
||||
|
||||
static inline void ipu_smfc_write(struct ipu_soc *ipu,
|
||||
u32 value, unsigned offset)
|
||||
{
|
||||
writel(value, ipu->smfc_reg + offset);
|
||||
}
|
||||
|
||||
static inline u32 ipu_vdi_read(struct ipu_soc *ipu, unsigned offset)
|
||||
{
|
||||
return readl(ipu->vdi_reg + offset);
|
||||
}
|
||||
|
||||
static inline void ipu_vdi_write(struct ipu_soc *ipu,
|
||||
u32 value, unsigned offset)
|
||||
{
|
||||
writel(value, ipu->vdi_reg + offset);
|
||||
}
|
||||
|
||||
static inline u32 ipu_ic_read(struct ipu_soc *ipu, unsigned offset)
|
||||
{
|
||||
return readl(ipu->ic_reg + offset);
|
||||
}
|
||||
|
||||
static inline void ipu_ic_write(struct ipu_soc *ipu,
|
||||
u32 value, unsigned offset)
|
||||
{
|
||||
writel(value, ipu->ic_reg + offset);
|
||||
}
|
||||
|
||||
int register_ipu_device(struct ipu_soc *ipu, int id);
|
||||
void unregister_ipu_device(struct ipu_soc *ipu, int id);
|
||||
ipu_color_space_t format_to_colorspace(uint32_t fmt);
|
||||
bool ipu_pixel_format_has_alpha(uint32_t fmt);
|
||||
|
||||
void ipu_dump_registers(struct ipu_soc *ipu);
|
||||
|
||||
uint32_t _ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel);
|
||||
|
||||
void ipu_disp_init(struct ipu_soc *ipu);
|
||||
void _ipu_init_dc_mappings(struct ipu_soc *ipu);
|
||||
int _ipu_dp_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t in_pixel_fmt,
|
||||
uint32_t out_pixel_fmt);
|
||||
void _ipu_dp_uninit(struct ipu_soc *ipu, ipu_channel_t channel);
|
||||
void _ipu_dc_init(struct ipu_soc *ipu, int dc_chan, int di, bool interlaced, uint32_t pixel_fmt);
|
||||
void _ipu_dc_uninit(struct ipu_soc *ipu, int dc_chan);
|
||||
void _ipu_dp_dc_enable(struct ipu_soc *ipu, ipu_channel_t channel);
|
||||
void _ipu_dp_dc_disable(struct ipu_soc *ipu, ipu_channel_t channel, bool swap);
|
||||
void _ipu_dmfc_init(struct ipu_soc *ipu, int dmfc_type, int first);
|
||||
void _ipu_dmfc_set_wait4eot(struct ipu_soc *ipu, int dma_chan, int width);
|
||||
void _ipu_dmfc_set_burst_size(struct ipu_soc *ipu, int dma_chan, int burst_size);
|
||||
int _ipu_disp_chan_is_interlaced(struct ipu_soc *ipu, ipu_channel_t channel);
|
||||
|
||||
void _ipu_ic_enable_task(struct ipu_soc *ipu, ipu_channel_t channel);
|
||||
void _ipu_ic_disable_task(struct ipu_soc *ipu, ipu_channel_t channel);
|
||||
int _ipu_ic_init_prpvf(struct ipu_soc *ipu, ipu_channel_params_t *params,
|
||||
bool src_is_csi);
|
||||
void _ipu_vdi_init(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params);
|
||||
void _ipu_vdi_uninit(struct ipu_soc *ipu);
|
||||
void _ipu_ic_uninit_prpvf(struct ipu_soc *ipu);
|
||||
void _ipu_ic_init_rotate_vf(struct ipu_soc *ipu, ipu_channel_params_t *params);
|
||||
void _ipu_ic_uninit_rotate_vf(struct ipu_soc *ipu);
|
||||
void _ipu_ic_init_csi(struct ipu_soc *ipu, ipu_channel_params_t *params);
|
||||
void _ipu_ic_uninit_csi(struct ipu_soc *ipu);
|
||||
int _ipu_ic_init_prpenc(struct ipu_soc *ipu, ipu_channel_params_t *params,
|
||||
bool src_is_csi);
|
||||
void _ipu_ic_uninit_prpenc(struct ipu_soc *ipu);
|
||||
void _ipu_ic_init_rotate_enc(struct ipu_soc *ipu, ipu_channel_params_t *params);
|
||||
void _ipu_ic_uninit_rotate_enc(struct ipu_soc *ipu);
|
||||
int _ipu_ic_init_pp(struct ipu_soc *ipu, ipu_channel_params_t *params);
|
||||
void _ipu_ic_uninit_pp(struct ipu_soc *ipu);
|
||||
void _ipu_ic_init_rotate_pp(struct ipu_soc *ipu, ipu_channel_params_t *params);
|
||||
void _ipu_ic_uninit_rotate_pp(struct ipu_soc *ipu);
|
||||
int _ipu_ic_idma_init(struct ipu_soc *ipu, int dma_chan, uint16_t width, uint16_t height,
|
||||
int burst_size, ipu_rotate_mode_t rot);
|
||||
void _ipu_vdi_toggle_top_field_man(struct ipu_soc *ipu);
|
||||
int _ipu_csi_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t csi);
|
||||
int _ipu_csi_set_mipi_di(struct ipu_soc *ipu, uint32_t num, uint32_t di_val, uint32_t csi);
|
||||
void ipu_csi_set_test_generator(struct ipu_soc *ipu, bool active, uint32_t r_value,
|
||||
uint32_t g_value, uint32_t b_value,
|
||||
uint32_t pix_clk, uint32_t csi);
|
||||
void _ipu_csi_ccir_err_detection_enable(struct ipu_soc *ipu, uint32_t csi);
|
||||
void _ipu_csi_ccir_err_detection_disable(struct ipu_soc *ipu, uint32_t csi);
|
||||
void _ipu_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel);
|
||||
void _ipu_smfc_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t mipi_id, uint32_t csi);
|
||||
void _ipu_smfc_set_burst_size(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t bs);
|
||||
void _ipu_dp_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3]);
|
||||
int32_t _ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
|
||||
int16_t x_pos, int16_t y_pos);
|
||||
int32_t _ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
|
||||
int16_t *x_pos, int16_t *y_pos);
|
||||
void _ipu_get(struct ipu_soc *ipu);
|
||||
void _ipu_put(struct ipu_soc *ipu);
|
||||
|
||||
struct clk *clk_register_mux_pix_clk(struct device *dev, const char *name,
|
||||
const char **parent_names, u8 num_parents, unsigned long flags,
|
||||
u8 ipu_id, u8 di_id, u8 clk_mux_flags);
|
||||
struct clk *clk_register_div_pix_clk(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
u8 ipu_id, u8 di_id, u8 clk_div_flags);
|
||||
struct clk *clk_register_gate_pix_clk(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
u8 ipu_id, u8 di_id, u8 clk_gate_flags);
|
||||
#endif /* __INCLUDE_IPU_PRV_H__ */
|
|
@ -0,0 +1,702 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* @file ipu_regs.h
|
||||
*
|
||||
* @brief IPU Register definitions
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
#ifndef __IPU_REGS_INCLUDED__
|
||||
#define __IPU_REGS_INCLUDED__
|
||||
|
||||
#include "ipu_prv.h"
|
||||
|
||||
#define IPU_MCU_T_DEFAULT 8
|
||||
|
||||
/* Register addresses */
|
||||
/* IPU Common registers */
|
||||
#define IPU_CM_REG(offset) (offset)
|
||||
|
||||
#define IPU_CONF IPU_CM_REG(0)
|
||||
#define IPU_SRM_PRI1 IPU_CM_REG(0x00A0)
|
||||
#define IPU_SRM_PRI2 IPU_CM_REG(0x00A4)
|
||||
#define IPU_FS_PROC_FLOW1 IPU_CM_REG(0x00A8)
|
||||
#define IPU_FS_PROC_FLOW2 IPU_CM_REG(0x00AC)
|
||||
#define IPU_FS_PROC_FLOW3 IPU_CM_REG(0x00B0)
|
||||
#define IPU_FS_DISP_FLOW1 IPU_CM_REG(0x00B4)
|
||||
#define IPU_FS_DISP_FLOW2 IPU_CM_REG(0x00B8)
|
||||
#define IPU_SKIP IPU_CM_REG(0x00BC)
|
||||
#define IPU_DISP_ALT_CONF IPU_CM_REG(0x00C0)
|
||||
#define IPU_DISP_GEN IPU_CM_REG(0x00C4)
|
||||
#define IPU_DISP_ALT1 IPU_CM_REG(0x00C8)
|
||||
#define IPU_DISP_ALT2 IPU_CM_REG(0x00CC)
|
||||
#define IPU_DISP_ALT3 IPU_CM_REG(0x00D0)
|
||||
#define IPU_DISP_ALT4 IPU_CM_REG(0x00D4)
|
||||
#define IPU_SNOOP IPU_CM_REG(0x00D8)
|
||||
#define IPU_MEM_RST IPU_CM_REG(0x00DC)
|
||||
#define IPU_PM IPU_CM_REG(0x00E0)
|
||||
#define IPU_GPR IPU_CM_REG(0x00E4)
|
||||
#define IPU_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
|
||||
#define IPU_ALT_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
|
||||
/*
|
||||
* IPUv3D doesn't support triple buffer, so point
|
||||
* IPU_CHA_TRB_MODE_SEL, IPU_CHA_TRIPLE_CUR_BUF and
|
||||
* IPU_CHA_BUF2_RDY to readonly
|
||||
* IPU_ALT_CUR_BUF0 for IPUv3D.
|
||||
*/
|
||||
#define IPU_CHA_TRB_MODE_SEL(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
|
||||
(0x0178 + 4 * ((ch) / 32)) : \
|
||||
(0x012C); })
|
||||
#define IPU_CHA_TRIPLE_CUR_BUF(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
|
||||
(0x0258 + \
|
||||
4 * (((ch) * 2) / 32)) : \
|
||||
(0x012C); })
|
||||
#define IPU_CHA_BUF2_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
|
||||
(0x0288 + 4 * ((ch) / 32)) : \
|
||||
(0x012C); })
|
||||
#define IPU_CHA_CUR_BUF(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
|
||||
(0x023C + 4 * ((ch) / 32)) : \
|
||||
(0x0124 + 4 * ((ch) / 32)); })
|
||||
#define IPU_ALT_CUR_BUF0(type) IPU_CM_REG({(type) >= IPUv3EX ? \
|
||||
(0x0244) : \
|
||||
(0x012C); })
|
||||
#define IPU_ALT_CUR_BUF1(type) IPU_CM_REG({(type) >= IPUv3EX ? \
|
||||
(0x0248) : \
|
||||
(0x0130); })
|
||||
#define IPU_SRM_STAT(type) IPU_CM_REG({(type) >= IPUv3EX ? \
|
||||
(0x024C) : \
|
||||
(0x0134); })
|
||||
#define IPU_PROC_TASK_STAT(type) IPU_CM_REG({(type) >= IPUv3EX ? \
|
||||
(0x0250) : \
|
||||
(0x0138); })
|
||||
#define IPU_DISP_TASK_STAT(type) IPU_CM_REG({(type) >= IPUv3EX ? \
|
||||
(0x0254) : \
|
||||
(0x013C); })
|
||||
#define IPU_CHA_BUF0_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
|
||||
(0x0268 + 4 * ((ch) / 32)) : \
|
||||
(0x0140 + 4 * ((ch) / 32)); })
|
||||
#define IPU_CHA_BUF1_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
|
||||
(0x0270 + 4 * ((ch) / 32)) : \
|
||||
(0x0148 + 4 * ((ch) / 32)); })
|
||||
#define IPU_ALT_CHA_BUF0_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
|
||||
(0x0278 + 4 * ((ch) / 32)) : \
|
||||
(0x0158 + 4 * ((ch) / 32)); })
|
||||
#define IPU_ALT_CHA_BUF1_RDY(type, ch) IPU_CM_REG({(type) >= IPUv3EX ? \
|
||||
(0x0280 + 4 * ((ch) / 32)) : \
|
||||
(0x0160 + 4 * ((ch) / 32)); })
|
||||
|
||||
#define IPU_INT_CTRL(n) IPU_CM_REG(0x003C + 4 * ((n) - 1))
|
||||
#define IPU_INT_STAT(type, n) IPU_CM_REG({(type) >= IPUv3EX ? \
|
||||
(0x0200 + 4 * ((n) - 1)) : \
|
||||
(0x00E8 + 4 * ((n) - 1)); })
|
||||
|
||||
#define IPUIRQ_2_STATREG(type, irq) IPU_CM_REG(IPU_INT_STAT((type), 1) + 4 \
|
||||
* ((irq) / 32))
|
||||
#define IPUIRQ_2_CTRLREG(irq) IPU_CM_REG(IPU_INT_CTRL(1) + 4 * ((irq) / 32))
|
||||
#define IPUIRQ_2_MASK(irq) (1UL << ((irq) & 0x1F))
|
||||
|
||||
/* IPU VDI registers */
|
||||
#define IPU_VDI_REG(offset) (offset)
|
||||
|
||||
#define VDI_FSIZE IPU_VDI_REG(0)
|
||||
#define VDI_C IPU_VDI_REG(0x0004)
|
||||
|
||||
/* IPU CSI Registers */
|
||||
#define IPU_CSI_REG(offset) (offset)
|
||||
|
||||
#define CSI_SENS_CONF IPU_CSI_REG(0)
|
||||
#define CSI_SENS_FRM_SIZE IPU_CSI_REG(0x0004)
|
||||
#define CSI_ACT_FRM_SIZE IPU_CSI_REG(0x0008)
|
||||
#define CSI_OUT_FRM_CTRL IPU_CSI_REG(0x000C)
|
||||
#define CSI_TST_CTRL IPU_CSI_REG(0x0010)
|
||||
#define CSI_CCIR_CODE_1 IPU_CSI_REG(0x0014)
|
||||
#define CSI_CCIR_CODE_2 IPU_CSI_REG(0x0018)
|
||||
#define CSI_CCIR_CODE_3 IPU_CSI_REG(0x001C)
|
||||
#define CSI_MIPI_DI IPU_CSI_REG(0x0020)
|
||||
#define CSI_SKIP IPU_CSI_REG(0x0024)
|
||||
#define CSI_CPD_CTRL IPU_CSI_REG(0x0028)
|
||||
#define CSI_CPD_RC(n) IPU_CSI_REG(0x002C + 4 * (n))
|
||||
#define CSI_CPD_RS(n) IPU_CSI_REG(0x004C + 4 * (n))
|
||||
#define CSI_CPD_GRC(n) IPU_CSI_REG(0x005C + 4 * (n))
|
||||
#define CSI_CPD_GRS(n) IPU_CSI_REG(0x007C + 4 * (n))
|
||||
#define CSI_CPD_GBC(n) IPU_CSI_REG(0x008C + 4 * (n))
|
||||
#define CSI_CPD_GBS(n) IPU_CSI_REG(0x00AC + 4 * (n))
|
||||
#define CSI_CPD_BC(n) IPU_CSI_REG(0x00BC + 4 * (n))
|
||||
#define CSI_CPD_BS(n) IPU_CSI_REG(0x00DC + 4 * (n))
|
||||
#define CSI_CPD_OFFSET1 IPU_CSI_REG(0x00EC)
|
||||
#define CSI_CPD_OFFSET2 IPU_CSI_REG(0x00F0)
|
||||
|
||||
/* IPU SMFC Registers */
|
||||
#define IPU_SMFC_REG(offset) (offset)
|
||||
|
||||
#define SMFC_MAP IPU_SMFC_REG(0)
|
||||
#define SMFC_WMC IPU_SMFC_REG(0x0004)
|
||||
#define SMFC_BS IPU_SMFC_REG(0x0008)
|
||||
|
||||
/* IPU IC Registers */
|
||||
#define IPU_IC_REG(offset) (offset)
|
||||
|
||||
#define IC_CONF IPU_IC_REG(0)
|
||||
#define IC_PRP_ENC_RSC IPU_IC_REG(0x0004)
|
||||
#define IC_PRP_VF_RSC IPU_IC_REG(0x0008)
|
||||
#define IC_PP_RSC IPU_IC_REG(0x000C)
|
||||
#define IC_CMBP_1 IPU_IC_REG(0x0010)
|
||||
#define IC_CMBP_2 IPU_IC_REG(0x0014)
|
||||
#define IC_IDMAC_1 IPU_IC_REG(0x0018)
|
||||
#define IC_IDMAC_2 IPU_IC_REG(0x001C)
|
||||
#define IC_IDMAC_3 IPU_IC_REG(0x0020)
|
||||
#define IC_IDMAC_4 IPU_IC_REG(0x0024)
|
||||
|
||||
/* IPU IDMAC Registers */
|
||||
#define IPU_IDMAC_REG(offset) (offset)
|
||||
|
||||
#define IDMAC_CONF IPU_IDMAC_REG(0x0000)
|
||||
#define IDMAC_CHA_EN(ch) IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
|
||||
#define IDMAC_SEP_ALPHA IPU_IDMAC_REG(0x000C)
|
||||
#define IDMAC_ALT_SEP_ALPHA IPU_IDMAC_REG(0x0010)
|
||||
#define IDMAC_CHA_PRI(ch) IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
|
||||
#define IDMAC_WM_EN(ch) IPU_IDMAC_REG(0x001C + 4 * ((ch) / 32))
|
||||
#define IDMAC_CH_LOCK_EN_1(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
|
||||
(0x0024) : 0; })
|
||||
#define IDMAC_CH_LOCK_EN_2(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
|
||||
(0x0028) : \
|
||||
(0x0024); })
|
||||
#define IDMAC_SUB_ADDR_0(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
|
||||
(0x002C) : \
|
||||
(0x0028); })
|
||||
#define IDMAC_SUB_ADDR_1(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
|
||||
(0x0030) : \
|
||||
(0x002C); })
|
||||
#define IDMAC_SUB_ADDR_2(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
|
||||
(0x0034) : \
|
||||
(0x0030); })
|
||||
/*
|
||||
* IPUv3D doesn't support IDMAC_SUB_ADDR_3 and IDMAC_SUB_ADDR_4,
|
||||
* so point them to readonly IDMAC_CHA_BUSY1 for IPUv3D.
|
||||
*/
|
||||
#define IDMAC_SUB_ADDR_3(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
|
||||
(0x0038) : \
|
||||
(0x0040); })
|
||||
#define IDMAC_SUB_ADDR_4(type) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
|
||||
(0x003C) : \
|
||||
(0x0040); })
|
||||
#define IDMAC_BAND_EN(type, ch) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
|
||||
(0x0040 + 4 * ((ch) / 32)) : \
|
||||
(0x0034 + 4 * ((ch) / 32)); })
|
||||
#define IDMAC_CHA_BUSY(type, ch) IPU_IDMAC_REG({(type) >= IPUv3EX ? \
|
||||
(0x0100 + 4 * ((ch) / 32)) : \
|
||||
(0x0040 + 4 * ((ch) / 32)); })
|
||||
|
||||
/* IPU DI Registers */
|
||||
#define IPU_DI_REG(offset) (offset)
|
||||
|
||||
#define DI_GENERAL IPU_DI_REG(0)
|
||||
#define DI_BS_CLKGEN0 IPU_DI_REG(0x0004)
|
||||
#define DI_BS_CLKGEN1 IPU_DI_REG(0x0008)
|
||||
#define DI_SW_GEN0(gen) IPU_DI_REG(0x000C + 4 * ((gen) - 1))
|
||||
#define DI_SW_GEN1(gen) IPU_DI_REG(0x0030 + 4 * ((gen) - 1))
|
||||
#define DI_STP_REP(gen) IPU_DI_REG(0x0148 + 4 * (((gen) - 1) / 2))
|
||||
#define DI_SYNC_AS_GEN IPU_DI_REG(0x0054)
|
||||
#define DI_DW_GEN(gen) IPU_DI_REG(0x0058 + 4 * (gen))
|
||||
#define DI_DW_SET(gen, set) IPU_DI_REG(0x0088 + 4 * ((gen) + 0xC * (set)))
|
||||
#define DI_SER_CONF IPU_DI_REG(0x015C)
|
||||
#define DI_SSC IPU_DI_REG(0x0160)
|
||||
#define DI_POL IPU_DI_REG(0x0164)
|
||||
#define DI_AW0 IPU_DI_REG(0x0168)
|
||||
#define DI_AW1 IPU_DI_REG(0x016C)
|
||||
#define DI_SCR_CONF IPU_DI_REG(0x0170)
|
||||
#define DI_STAT IPU_DI_REG(0x0174)
|
||||
|
||||
/* IPU DMFC Registers */
|
||||
#define IPU_DMFC_REG(offset) (offset)
|
||||
|
||||
#define DMFC_RD_CHAN IPU_DMFC_REG(0)
|
||||
#define DMFC_WR_CHAN IPU_DMFC_REG(0x0004)
|
||||
#define DMFC_WR_CHAN_DEF IPU_DMFC_REG(0x0008)
|
||||
#define DMFC_DP_CHAN IPU_DMFC_REG(0x000C)
|
||||
#define DMFC_DP_CHAN_DEF IPU_DMFC_REG(0x0010)
|
||||
#define DMFC_GENERAL1 IPU_DMFC_REG(0x0014)
|
||||
#define DMFC_GENERAL2 IPU_DMFC_REG(0x0018)
|
||||
#define DMFC_IC_CTRL IPU_DMFC_REG(0x001C)
|
||||
#define DMFC_STAT IPU_DMFC_REG(0x0020)
|
||||
|
||||
/* IPU DC Registers */
|
||||
#define IPU_DC_REG(offset) (offset)
|
||||
|
||||
#define DC_MAP_CONF_PTR(n) IPU_DC_REG(0x0108 + ((n) & ~0x1) * 2)
|
||||
#define DC_MAP_CONF_VAL(n) IPU_DC_REG(0x0144 + ((n) & ~0x1) * 2)
|
||||
|
||||
#define _RL_CH_2_OFFSET(ch) (((ch) == 0) ? 8 : ( \
|
||||
((ch) == 1) ? 0x24 : ( \
|
||||
((ch) == 2) ? 0x40 : ( \
|
||||
((ch) == 5) ? 0x64 : ( \
|
||||
((ch) == 6) ? 0x80 : ( \
|
||||
((ch) == 8) ? 0x9C : ( \
|
||||
((ch) == 9) ? 0xBC : (-1))))))))
|
||||
#define DC_RL_CH(ch, evt) IPU_DC_REG(_RL_CH_2_OFFSET(ch) + \
|
||||
((evt) & ~0x1) * 2)
|
||||
|
||||
#define DC_EVT_NF 0
|
||||
#define DC_EVT_NL 1
|
||||
#define DC_EVT_EOF 2
|
||||
#define DC_EVT_NFIELD 3
|
||||
#define DC_EVT_EOL 4
|
||||
#define DC_EVT_EOFIELD 5
|
||||
#define DC_EVT_NEW_ADDR 6
|
||||
#define DC_EVT_NEW_CHAN 7
|
||||
#define DC_EVT_NEW_DATA 8
|
||||
|
||||
#define DC_EVT_NEW_ADDR_W_0 0
|
||||
#define DC_EVT_NEW_ADDR_W_1 1
|
||||
#define DC_EVT_NEW_CHAN_W_0 2
|
||||
#define DC_EVT_NEW_CHAN_W_1 3
|
||||
#define DC_EVT_NEW_DATA_W_0 4
|
||||
#define DC_EVT_NEW_DATA_W_1 5
|
||||
#define DC_EVT_NEW_ADDR_R_0 6
|
||||
#define DC_EVT_NEW_ADDR_R_1 7
|
||||
#define DC_EVT_NEW_CHAN_R_0 8
|
||||
#define DC_EVT_NEW_CHAN_R_1 9
|
||||
#define DC_EVT_NEW_DATA_R_0 10
|
||||
#define DC_EVT_NEW_DATA_R_1 11
|
||||
#define DC_EVEN_UGDE0 12
|
||||
#define DC_ODD_UGDE0 13
|
||||
#define DC_EVEN_UGDE1 14
|
||||
#define DC_ODD_UGDE1 15
|
||||
#define DC_EVEN_UGDE2 16
|
||||
#define DC_ODD_UGDE2 17
|
||||
#define DC_EVEN_UGDE3 18
|
||||
#define DC_ODD_UGDE3 19
|
||||
|
||||
#define dc_ch_offset(ch) \
|
||||
({ \
|
||||
const u8 _offset[] = { \
|
||||
0, 0x1C, 0x38, 0x54, 0x58, 0x5C, 0x78, 0, 0x94, 0xB4}; \
|
||||
_offset[ch]; \
|
||||
})
|
||||
#define DC_WR_CH_CONF(ch) IPU_DC_REG(dc_ch_offset(ch))
|
||||
#define DC_WR_CH_ADDR(ch) IPU_DC_REG(dc_ch_offset(ch) + 4)
|
||||
|
||||
#define DC_WR_CH_CONF_1 IPU_DC_REG(0x001C)
|
||||
#define DC_WR_CH_ADDR_1 IPU_DC_REG(0x0020)
|
||||
#define DC_WR_CH_CONF_5 IPU_DC_REG(0x005C)
|
||||
#define DC_WR_CH_ADDR_5 IPU_DC_REG(0x0060)
|
||||
#define DC_GEN IPU_DC_REG(0x00D4)
|
||||
#define DC_DISP_CONF1(disp) IPU_DC_REG(0x00D8 + 4 * (disp))
|
||||
#define DC_DISP_CONF2(disp) IPU_DC_REG(0x00E8 + 4 * (disp))
|
||||
#define DC_STAT IPU_DC_REG(0x01C8)
|
||||
#define DC_UGDE_0(evt) IPU_DC_REG(0x0174 + 16 * (evt))
|
||||
#define DC_UGDE_1(evt) IPU_DC_REG(0x0178 + 16 * (evt))
|
||||
#define DC_UGDE_2(evt) IPU_DC_REG(0x017C + 16 * (evt))
|
||||
#define DC_UGDE_3(evt) IPU_DC_REG(0x0180 + 16 * (evt))
|
||||
|
||||
/* IPU DP Registers */
|
||||
#define IPU_DP_REG(offset) (offset)
|
||||
|
||||
#define DP_SYNC 0
|
||||
#define DP_ASYNC0 0x60
|
||||
#define DP_ASYNC1 0xBC
|
||||
#define DP_COM_CONF(flow) IPU_DP_REG(flow)
|
||||
#define DP_GRAPH_WIND_CTRL(flow) IPU_DP_REG(0x0004 + (flow))
|
||||
#define DP_FG_POS(flow) IPU_DP_REG(0x0008 + (flow))
|
||||
#define DP_GAMMA_C(flow, i) IPU_DP_REG(0x0014 + (flow) + 4 * (i))
|
||||
#define DP_GAMMA_S(flow, i) IPU_DP_REG(0x0034 + (flow) + 4 * (i))
|
||||
#define DP_CSC_A_0(flow) IPU_DP_REG(0x0044 + (flow))
|
||||
#define DP_CSC_A_1(flow) IPU_DP_REG(0x0048 + (flow))
|
||||
#define DP_CSC_A_2(flow) IPU_DP_REG(0x004C + (flow))
|
||||
#define DP_CSC_A_3(flow) IPU_DP_REG(0x0050 + (flow))
|
||||
#define DP_CSC_0(flow) IPU_DP_REG(0x0054 + (flow))
|
||||
#define DP_CSC_1(flow) IPU_DP_REG(0x0058 + (flow))
|
||||
|
||||
enum {
|
||||
IPU_CONF_CSI0_EN = 0x00000001,
|
||||
IPU_CONF_CSI1_EN = 0x00000002,
|
||||
IPU_CONF_IC_EN = 0x00000004,
|
||||
IPU_CONF_ROT_EN = 0x00000008,
|
||||
IPU_CONF_ISP_EN = 0x00000010,
|
||||
IPU_CONF_DP_EN = 0x00000020,
|
||||
IPU_CONF_DI0_EN = 0x00000040,
|
||||
IPU_CONF_DI1_EN = 0x00000080,
|
||||
IPU_CONF_DMFC_EN = 0x00000400,
|
||||
IPU_CONF_SMFC_EN = 0x00000100,
|
||||
IPU_CONF_DC_EN = 0x00000200,
|
||||
IPU_CONF_VDI_EN = 0x00001000,
|
||||
IPU_CONF_IDMAC_DIS = 0x00400000,
|
||||
IPU_CONF_IC_DMFC_SEL = 0x02000000,
|
||||
IPU_CONF_IC_DMFC_SYNC = 0x04000000,
|
||||
IPU_CONF_VDI_DMFC_SYNC = 0x08000000,
|
||||
IPU_CONF_CSI0_DATA_SOURCE = 0x10000000,
|
||||
IPU_CONF_CSI0_DATA_SOURCE_OFFSET = 28,
|
||||
IPU_CONF_CSI1_DATA_SOURCE = 0x20000000,
|
||||
IPU_CONF_IC_INPUT = 0x40000000,
|
||||
IPU_CONF_CSI_SEL = 0x80000000,
|
||||
|
||||
DI0_COUNTER_RELEASE = 0x01000000,
|
||||
DI1_COUNTER_RELEASE = 0x02000000,
|
||||
|
||||
FS_PRPVF_ROT_SRC_SEL_MASK = 0x00000F00,
|
||||
FS_PRPVF_ROT_SRC_SEL_OFFSET = 8,
|
||||
FS_PRPENC_ROT_SRC_SEL_MASK = 0x0000000F,
|
||||
FS_PRPENC_ROT_SRC_SEL_OFFSET = 0,
|
||||
FS_PP_ROT_SRC_SEL_MASK = 0x000F0000,
|
||||
FS_PP_ROT_SRC_SEL_OFFSET = 16,
|
||||
FS_PP_SRC_SEL_MASK = 0x0000F000,
|
||||
FS_PP_SRC_SEL_VDOA = 0x00008000,
|
||||
FS_PP_SRC_SEL_OFFSET = 12,
|
||||
FS_PRP_SRC_SEL_MASK = 0x0F000000,
|
||||
FS_PRP_SRC_SEL_OFFSET = 24,
|
||||
FS_VF_IN_VALID = 0x80000000,
|
||||
FS_ENC_IN_VALID = 0x40000000,
|
||||
FS_VDI_SRC_SEL_MASK = 0x30000000,
|
||||
FS_VDI_SRC_SEL_VDOA = 0x20000000,
|
||||
FS_VDOA_DEST_SEL_MASK = 0x00030000,
|
||||
FS_VDOA_DEST_SEL_VDI = 0x00020000,
|
||||
FS_VDOA_DEST_SEL_IC = 0x00010000,
|
||||
FS_VDI_SRC_SEL_OFFSET = 28,
|
||||
|
||||
|
||||
FS_PRPENC_DEST_SEL_MASK = 0x0000000F,
|
||||
FS_PRPENC_DEST_SEL_OFFSET = 0,
|
||||
FS_PRPVF_DEST_SEL_MASK = 0x000000F0,
|
||||
FS_PRPVF_DEST_SEL_OFFSET = 4,
|
||||
FS_PRPVF_ROT_DEST_SEL_MASK = 0x00000F00,
|
||||
FS_PRPVF_ROT_DEST_SEL_OFFSET = 8,
|
||||
FS_PP_DEST_SEL_MASK = 0x0000F000,
|
||||
FS_PP_DEST_SEL_OFFSET = 12,
|
||||
FS_PP_ROT_DEST_SEL_MASK = 0x000F0000,
|
||||
FS_PP_ROT_DEST_SEL_OFFSET = 16,
|
||||
FS_PRPENC_ROT_DEST_SEL_MASK = 0x00F00000,
|
||||
FS_PRPENC_ROT_DEST_SEL_OFFSET = 20,
|
||||
|
||||
FS_SMFC0_DEST_SEL_MASK = 0x0000000F,
|
||||
FS_SMFC0_DEST_SEL_OFFSET = 0,
|
||||
FS_SMFC1_DEST_SEL_MASK = 0x00000070,
|
||||
FS_SMFC1_DEST_SEL_OFFSET = 4,
|
||||
FS_SMFC2_DEST_SEL_MASK = 0x00000780,
|
||||
FS_SMFC2_DEST_SEL_OFFSET = 7,
|
||||
FS_SMFC3_DEST_SEL_MASK = 0x00003800,
|
||||
FS_SMFC3_DEST_SEL_OFFSET = 11,
|
||||
|
||||
FS_DC1_SRC_SEL_MASK = 0x00F00000,
|
||||
FS_DC1_SRC_SEL_OFFSET = 20,
|
||||
FS_DC2_SRC_SEL_MASK = 0x000F0000,
|
||||
FS_DC2_SRC_SEL_OFFSET = 16,
|
||||
FS_DP_SYNC0_SRC_SEL_MASK = 0x0000000F,
|
||||
FS_DP_SYNC0_SRC_SEL_OFFSET = 0,
|
||||
FS_DP_SYNC1_SRC_SEL_MASK = 0x000000F0,
|
||||
FS_DP_SYNC1_SRC_SEL_OFFSET = 4,
|
||||
FS_DP_ASYNC0_SRC_SEL_MASK = 0x00000F00,
|
||||
FS_DP_ASYNC0_SRC_SEL_OFFSET = 8,
|
||||
FS_DP_ASYNC1_SRC_SEL_MASK = 0x0000F000,
|
||||
FS_DP_ASYNC1_SRC_SEL_OFFSET = 12,
|
||||
|
||||
FS_AUTO_REF_PER_MASK = 0,
|
||||
FS_AUTO_REF_PER_OFFSET = 16,
|
||||
|
||||
TSTAT_VF_MASK = 0x0000000C,
|
||||
TSTAT_VF_OFFSET = 2,
|
||||
TSTAT_VF_ROT_MASK = 0x00000300,
|
||||
TSTAT_VF_ROT_OFFSET = 8,
|
||||
TSTAT_ENC_MASK = 0x00000003,
|
||||
TSTAT_ENC_OFFSET = 0,
|
||||
TSTAT_ENC_ROT_MASK = 0x000000C0,
|
||||
TSTAT_ENC_ROT_OFFSET = 6,
|
||||
TSTAT_PP_MASK = 0x00000030,
|
||||
TSTAT_PP_OFFSET = 4,
|
||||
TSTAT_PP_ROT_MASK = 0x00000C00,
|
||||
TSTAT_PP_ROT_OFFSET = 10,
|
||||
|
||||
TASK_STAT_IDLE = 0,
|
||||
TASK_STAT_ACTIVE = 1,
|
||||
TASK_STAT_WAIT4READY = 2,
|
||||
|
||||
/* IDMAC register bits */
|
||||
IDMAC_CONF_USED_BUFS_EN_R = 0x02000000,
|
||||
IDMAC_CONF_USED_BUFS_MAX_R_MASK = 0x01E00000,
|
||||
IDMAC_CONF_USED_BUFS_MAX_R_OFFSET = 21,
|
||||
IDMAC_CONF_USED_BUFS_EN_W = 0x00100000,
|
||||
IDMAC_CONF_USED_BUFS_MAX_W_MASK = 0x000E0000,
|
||||
IDMAC_CONF_USED_BUFS_MAX_W_OFFSET = 17,
|
||||
|
||||
/* Image Converter Register bits */
|
||||
IC_CONF_PRPENC_EN = 0x00000001,
|
||||
IC_CONF_PRPENC_CSC1 = 0x00000002,
|
||||
IC_CONF_PRPENC_ROT_EN = 0x00000004,
|
||||
IC_CONF_PRPVF_EN = 0x00000100,
|
||||
IC_CONF_PRPVF_CSC1 = 0x00000200,
|
||||
IC_CONF_PRPVF_CSC2 = 0x00000400,
|
||||
IC_CONF_PRPVF_CMB = 0x00000800,
|
||||
IC_CONF_PRPVF_ROT_EN = 0x00001000,
|
||||
IC_CONF_PP_EN = 0x00010000,
|
||||
IC_CONF_PP_CSC1 = 0x00020000,
|
||||
IC_CONF_PP_CSC2 = 0x00040000,
|
||||
IC_CONF_PP_CMB = 0x00080000,
|
||||
IC_CONF_PP_ROT_EN = 0x00100000,
|
||||
IC_CONF_IC_GLB_LOC_A = 0x10000000,
|
||||
IC_CONF_KEY_COLOR_EN = 0x20000000,
|
||||
IC_CONF_RWS_EN = 0x40000000,
|
||||
IC_CONF_CSI_MEM_WR_EN = 0x80000000,
|
||||
|
||||
IC_RSZ_MAX_RESIZE_RATIO = 0x00004000,
|
||||
|
||||
IC_IDMAC_1_CB0_BURST_16 = 0x00000001,
|
||||
IC_IDMAC_1_CB1_BURST_16 = 0x00000002,
|
||||
IC_IDMAC_1_CB2_BURST_16 = 0x00000004,
|
||||
IC_IDMAC_1_CB3_BURST_16 = 0x00000008,
|
||||
IC_IDMAC_1_CB4_BURST_16 = 0x00000010,
|
||||
IC_IDMAC_1_CB5_BURST_16 = 0x00000020,
|
||||
IC_IDMAC_1_CB6_BURST_16 = 0x00000040,
|
||||
IC_IDMAC_1_CB7_BURST_16 = 0x00000080,
|
||||
IC_IDMAC_1_PRPENC_ROT_MASK = 0x00003800,
|
||||
IC_IDMAC_1_PRPENC_ROT_OFFSET = 11,
|
||||
IC_IDMAC_1_PRPVF_ROT_MASK = 0x0001C000,
|
||||
IC_IDMAC_1_PRPVF_ROT_OFFSET = 14,
|
||||
IC_IDMAC_1_PP_ROT_MASK = 0x000E0000,
|
||||
IC_IDMAC_1_PP_ROT_OFFSET = 17,
|
||||
IC_IDMAC_1_PP_FLIP_RS = 0x00400000,
|
||||
IC_IDMAC_1_PRPVF_FLIP_RS = 0x00200000,
|
||||
IC_IDMAC_1_PRPENC_FLIP_RS = 0x00100000,
|
||||
|
||||
IC_IDMAC_2_PRPENC_HEIGHT_MASK = 0x000003FF,
|
||||
IC_IDMAC_2_PRPENC_HEIGHT_OFFSET = 0,
|
||||
IC_IDMAC_2_PRPVF_HEIGHT_MASK = 0x000FFC00,
|
||||
IC_IDMAC_2_PRPVF_HEIGHT_OFFSET = 10,
|
||||
IC_IDMAC_2_PP_HEIGHT_MASK = 0x3FF00000,
|
||||
IC_IDMAC_2_PP_HEIGHT_OFFSET = 20,
|
||||
|
||||
IC_IDMAC_3_PRPENC_WIDTH_MASK = 0x000003FF,
|
||||
IC_IDMAC_3_PRPENC_WIDTH_OFFSET = 0,
|
||||
IC_IDMAC_3_PRPVF_WIDTH_MASK = 0x000FFC00,
|
||||
IC_IDMAC_3_PRPVF_WIDTH_OFFSET = 10,
|
||||
IC_IDMAC_3_PP_WIDTH_MASK = 0x3FF00000,
|
||||
IC_IDMAC_3_PP_WIDTH_OFFSET = 20,
|
||||
|
||||
CSI_SENS_CONF_DATA_FMT_SHIFT = 8,
|
||||
CSI_SENS_CONF_DATA_FMT_MASK = 0x00000700,
|
||||
CSI_SENS_CONF_DATA_FMT_RGB_YUV444 = 0L,
|
||||
CSI_SENS_CONF_DATA_FMT_YUV422_YUYV = 1L,
|
||||
CSI_SENS_CONF_DATA_FMT_YUV422_UYVY = 2L,
|
||||
CSI_SENS_CONF_DATA_FMT_BAYER = 3L,
|
||||
CSI_SENS_CONF_DATA_FMT_RGB565 = 4L,
|
||||
CSI_SENS_CONF_DATA_FMT_RGB555 = 5L,
|
||||
CSI_SENS_CONF_DATA_FMT_RGB444 = 6L,
|
||||
CSI_SENS_CONF_DATA_FMT_JPEG = 7L,
|
||||
|
||||
CSI_SENS_CONF_VSYNC_POL_SHIFT = 0,
|
||||
CSI_SENS_CONF_HSYNC_POL_SHIFT = 1,
|
||||
CSI_SENS_CONF_DATA_POL_SHIFT = 2,
|
||||
CSI_SENS_CONF_PIX_CLK_POL_SHIFT = 3,
|
||||
CSI_SENS_CONF_SENS_PRTCL_MASK = 0x00000070L,
|
||||
CSI_SENS_CONF_SENS_PRTCL_SHIFT = 4,
|
||||
CSI_SENS_CONF_PACK_TIGHT_SHIFT = 7,
|
||||
CSI_SENS_CONF_DATA_WIDTH_SHIFT = 11,
|
||||
CSI_SENS_CONF_EXT_VSYNC_SHIFT = 15,
|
||||
CSI_SENS_CONF_DIVRATIO_SHIFT = 16,
|
||||
|
||||
CSI_SENS_CONF_DIVRATIO_MASK = 0x00FF0000L,
|
||||
CSI_SENS_CONF_DATA_DEST_SHIFT = 24,
|
||||
CSI_SENS_CONF_DATA_DEST_MASK = 0x07000000L,
|
||||
CSI_SENS_CONF_JPEG8_EN_SHIFT = 27,
|
||||
CSI_SENS_CONF_JPEG_EN_SHIFT = 28,
|
||||
CSI_SENS_CONF_FORCE_EOF_SHIFT = 29,
|
||||
CSI_SENS_CONF_DATA_EN_POL_SHIFT = 31,
|
||||
|
||||
CSI_DATA_DEST_ISP = 1L,
|
||||
CSI_DATA_DEST_IC = 2L,
|
||||
CSI_DATA_DEST_IDMAC = 4L,
|
||||
|
||||
CSI_CCIR_ERR_DET_EN = 0x01000000L,
|
||||
CSI_HORI_DOWNSIZE_EN = 0x80000000L,
|
||||
CSI_VERT_DOWNSIZE_EN = 0x40000000L,
|
||||
CSI_TEST_GEN_MODE_EN = 0x01000000L,
|
||||
|
||||
CSI_HSC_MASK = 0x1FFF0000,
|
||||
CSI_HSC_SHIFT = 16,
|
||||
CSI_VSC_MASK = 0x00000FFF,
|
||||
CSI_VSC_SHIFT = 0,
|
||||
|
||||
CSI_TEST_GEN_R_MASK = 0x000000FFL,
|
||||
CSI_TEST_GEN_R_SHIFT = 0,
|
||||
CSI_TEST_GEN_G_MASK = 0x0000FF00L,
|
||||
CSI_TEST_GEN_G_SHIFT = 8,
|
||||
CSI_TEST_GEN_B_MASK = 0x00FF0000L,
|
||||
CSI_TEST_GEN_B_SHIFT = 16,
|
||||
|
||||
CSI_MIPI_DI0_MASK = 0x000000FFL,
|
||||
CSI_MIPI_DI0_SHIFT = 0,
|
||||
CSI_MIPI_DI1_MASK = 0x0000FF00L,
|
||||
CSI_MIPI_DI1_SHIFT = 8,
|
||||
CSI_MIPI_DI2_MASK = 0x00FF0000L,
|
||||
CSI_MIPI_DI2_SHIFT = 16,
|
||||
CSI_MIPI_DI3_MASK = 0xFF000000L,
|
||||
CSI_MIPI_DI3_SHIFT = 24,
|
||||
|
||||
CSI_MAX_RATIO_SKIP_ISP_MASK = 0x00070000L,
|
||||
CSI_MAX_RATIO_SKIP_ISP_SHIFT = 16,
|
||||
CSI_SKIP_ISP_MASK = 0x00F80000L,
|
||||
CSI_SKIP_ISP_SHIFT = 19,
|
||||
CSI_MAX_RATIO_SKIP_SMFC_MASK = 0x00000007L,
|
||||
CSI_MAX_RATIO_SKIP_SMFC_SHIFT = 0,
|
||||
CSI_SKIP_SMFC_MASK = 0x000000F8L,
|
||||
CSI_SKIP_SMFC_SHIFT = 3,
|
||||
CSI_ID_2_SKIP_MASK = 0x00000300L,
|
||||
CSI_ID_2_SKIP_SHIFT = 8,
|
||||
|
||||
CSI_COLOR_FIRST_ROW_MASK = 0x00000002L,
|
||||
CSI_COLOR_FIRST_COMP_MASK = 0x00000001L,
|
||||
|
||||
SMFC_MAP_CH0_MASK = 0x00000007L,
|
||||
SMFC_MAP_CH0_SHIFT = 0,
|
||||
SMFC_MAP_CH1_MASK = 0x00000038L,
|
||||
SMFC_MAP_CH1_SHIFT = 3,
|
||||
SMFC_MAP_CH2_MASK = 0x000001C0L,
|
||||
SMFC_MAP_CH2_SHIFT = 6,
|
||||
SMFC_MAP_CH3_MASK = 0x00000E00L,
|
||||
SMFC_MAP_CH3_SHIFT = 9,
|
||||
|
||||
SMFC_WM0_SET_MASK = 0x00000007L,
|
||||
SMFC_WM0_SET_SHIFT = 0,
|
||||
SMFC_WM1_SET_MASK = 0x000001C0L,
|
||||
SMFC_WM1_SET_SHIFT = 6,
|
||||
SMFC_WM2_SET_MASK = 0x00070000L,
|
||||
SMFC_WM2_SET_SHIFT = 16,
|
||||
SMFC_WM3_SET_MASK = 0x01C00000L,
|
||||
SMFC_WM3_SET_SHIFT = 22,
|
||||
|
||||
SMFC_WM0_CLR_MASK = 0x00000038L,
|
||||
SMFC_WM0_CLR_SHIFT = 3,
|
||||
SMFC_WM1_CLR_MASK = 0x00000E00L,
|
||||
SMFC_WM1_CLR_SHIFT = 9,
|
||||
SMFC_WM2_CLR_MASK = 0x00380000L,
|
||||
SMFC_WM2_CLR_SHIFT = 19,
|
||||
SMFC_WM3_CLR_MASK = 0x0E000000L,
|
||||
SMFC_WM3_CLR_SHIFT = 25,
|
||||
|
||||
SMFC_BS0_MASK = 0x0000000FL,
|
||||
SMFC_BS0_SHIFT = 0,
|
||||
SMFC_BS1_MASK = 0x000000F0L,
|
||||
SMFC_BS1_SHIFT = 4,
|
||||
SMFC_BS2_MASK = 0x00000F00L,
|
||||
SMFC_BS2_SHIFT = 8,
|
||||
SMFC_BS3_MASK = 0x0000F000L,
|
||||
SMFC_BS3_SHIFT = 12,
|
||||
|
||||
PF_CONF_TYPE_MASK = 0x00000007,
|
||||
PF_CONF_TYPE_SHIFT = 0,
|
||||
PF_CONF_PAUSE_EN = 0x00000010,
|
||||
PF_CONF_RESET = 0x00008000,
|
||||
PF_CONF_PAUSE_ROW_MASK = 0x00FF0000,
|
||||
PF_CONF_PAUSE_ROW_SHIFT = 16,
|
||||
|
||||
DI_DW_GEN_ACCESS_SIZE_OFFSET = 24,
|
||||
DI_DW_GEN_COMPONENT_SIZE_OFFSET = 16,
|
||||
|
||||
DI_GEN_DI_CLK_EXT = 0x100000,
|
||||
DI_GEN_POLARITY_DISP_CLK = 0x00020000,
|
||||
DI_GEN_POLARITY_1 = 0x00000001,
|
||||
DI_GEN_POLARITY_2 = 0x00000002,
|
||||
DI_GEN_POLARITY_3 = 0x00000004,
|
||||
DI_GEN_POLARITY_4 = 0x00000008,
|
||||
DI_GEN_POLARITY_5 = 0x00000010,
|
||||
DI_GEN_POLARITY_6 = 0x00000020,
|
||||
DI_GEN_POLARITY_7 = 0x00000040,
|
||||
DI_GEN_POLARITY_8 = 0x00000080,
|
||||
|
||||
DI_POL_DRDY_DATA_POLARITY = 0x00000080,
|
||||
DI_POL_DRDY_POLARITY_15 = 0x00000010,
|
||||
|
||||
DI_VSYNC_SEL_OFFSET = 13,
|
||||
|
||||
DC_WR_CH_CONF_FIELD_MODE = 0x00000200,
|
||||
DC_WR_CH_CONF_PROG_TYPE_OFFSET = 5,
|
||||
DC_WR_CH_CONF_PROG_TYPE_MASK = 0x000000E0,
|
||||
DC_WR_CH_CONF_PROG_DI_ID = 0x00000004,
|
||||
DC_WR_CH_CONF_PROG_DISP_ID_OFFSET = 3,
|
||||
DC_WR_CH_CONF_PROG_DISP_ID_MASK = 0x00000018,
|
||||
|
||||
DC_UGDE_0_ODD_EN = 0x02000000,
|
||||
DC_UGDE_0_ID_CODED_MASK = 0x00000007,
|
||||
DC_UGDE_0_ID_CODED_OFFSET = 0,
|
||||
DC_UGDE_0_EV_PRIORITY_MASK = 0x00000078,
|
||||
DC_UGDE_0_EV_PRIORITY_OFFSET = 3,
|
||||
|
||||
DP_COM_CONF_FG_EN = 0x00000001,
|
||||
DP_COM_CONF_GWSEL = 0x00000002,
|
||||
DP_COM_CONF_GWAM = 0x00000004,
|
||||
DP_COM_CONF_GWCKE = 0x00000008,
|
||||
DP_COM_CONF_CSC_DEF_MASK = 0x00000300,
|
||||
DP_COM_CONF_CSC_DEF_OFFSET = 8,
|
||||
DP_COM_CONF_CSC_DEF_FG = 0x00000300,
|
||||
DP_COM_CONF_CSC_DEF_BG = 0x00000200,
|
||||
DP_COM_CONF_CSC_DEF_BOTH = 0x00000100,
|
||||
DP_COM_CONF_GAMMA_EN = 0x00001000,
|
||||
DP_COM_CONF_GAMMA_YUV_EN = 0x00002000,
|
||||
|
||||
DI_SER_CONF_LLA_SER_ACCESS = 0x00000020,
|
||||
DI_SER_CONF_SERIAL_CLK_POL = 0x00000010,
|
||||
DI_SER_CONF_SERIAL_DATA_POL = 0x00000008,
|
||||
DI_SER_CONF_SERIAL_RS_POL = 0x00000004,
|
||||
DI_SER_CONF_SERIAL_CS_POL = 0x00000002,
|
||||
DI_SER_CONF_WAIT4SERIAL = 0x00000001,
|
||||
|
||||
VDI_C_CH_420 = 0x00000000,
|
||||
VDI_C_CH_422 = 0x00000002,
|
||||
VDI_C_MOT_SEL_FULL = 0x00000008,
|
||||
VDI_C_MOT_SEL_LOW = 0x00000004,
|
||||
VDI_C_MOT_SEL_MED = 0x00000000,
|
||||
VDI_C_BURST_SIZE1_4 = 0x00000030,
|
||||
VDI_C_BURST_SIZE2_4 = 0x00000300,
|
||||
VDI_C_BURST_SIZE3_4 = 0x00003000,
|
||||
VDI_C_BURST_SIZE_MASK = 0xF,
|
||||
VDI_C_BURST_SIZE1_OFFSET = 4,
|
||||
VDI_C_BURST_SIZE2_OFFSET = 8,
|
||||
VDI_C_BURST_SIZE3_OFFSET = 12,
|
||||
VDI_C_VWM1_SET_1 = 0x00000000,
|
||||
VDI_C_VWM1_SET_2 = 0x00010000,
|
||||
VDI_C_VWM1_CLR_2 = 0x00080000,
|
||||
VDI_C_VWM3_SET_1 = 0x00000000,
|
||||
VDI_C_VWM3_SET_2 = 0x00400000,
|
||||
VDI_C_VWM3_CLR_2 = 0x02000000,
|
||||
VDI_C_TOP_FIELD_MAN_1 = 0x40000000,
|
||||
VDI_C_TOP_FIELD_AUTO_1 = 0x80000000,
|
||||
};
|
||||
|
||||
enum di_pins {
|
||||
DI_PIN11 = 0,
|
||||
DI_PIN12 = 1,
|
||||
DI_PIN13 = 2,
|
||||
DI_PIN14 = 3,
|
||||
DI_PIN15 = 4,
|
||||
DI_PIN16 = 5,
|
||||
DI_PIN17 = 6,
|
||||
DI_PIN_CS = 7,
|
||||
|
||||
DI_PIN_SER_CLK = 0,
|
||||
DI_PIN_SER_RS = 1,
|
||||
};
|
||||
|
||||
enum di_sync_wave {
|
||||
DI_SYNC_NONE = -1,
|
||||
DI_SYNC_CLK = 0,
|
||||
DI_SYNC_INT_HSYNC = 1,
|
||||
DI_SYNC_HSYNC = 2,
|
||||
DI_SYNC_VSYNC = 3,
|
||||
DI_SYNC_DE = 5,
|
||||
};
|
||||
|
||||
/* DC template opcodes */
|
||||
#define WROD(lf) (0x18 | (lf << 1))
|
||||
#define WRG (0x01)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,480 @@
|
|||
/*
|
||||
* Freescale PRE Register Definitions
|
||||
*
|
||||
* Copyright 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#ifndef __ARCH_ARM___PRE_H
|
||||
#define __ARCH_ARM___PRE_H
|
||||
|
||||
|
||||
#define HW_PRE_CTRL (0x00000000)
|
||||
#define HW_PRE_CTRL_SET (0x00000004)
|
||||
#define HW_PRE_CTRL_CLR (0x00000008)
|
||||
#define HW_PRE_CTRL_TOG (0x0000000c)
|
||||
|
||||
#define BM_PRE_CTRL_SFTRST 0x80000000
|
||||
#define BF_PRE_CTRL_SFTRST(v) \
|
||||
(((v) << 31) & BM_PRE_CTRL_SFTRST)
|
||||
#define BM_PRE_CTRL_CLKGATE 0x40000000
|
||||
#define BF_PRE_CTRL_CLKGATE(v) \
|
||||
(((v) << 30) & BM_PRE_CTRL_CLKGATE)
|
||||
#define BM_PRE_CTRL_TPR_RESET_SEL 0x20000000
|
||||
#define BF_PRE_CTRL_TPR_RESET_SEL(v) \
|
||||
(((v) << 29) & BM_PRE_CTRL_TPR_RESET_SEL)
|
||||
#define BM_PRE_CTRL_EN_REPEAT 0x10000000
|
||||
#define BF_PRE_CTRL_EN_REPEAT(v) \
|
||||
(((v) << 28) & BM_PRE_CTRL_EN_REPEAT)
|
||||
#define BP_PRE_CTRL_RSVD2 16
|
||||
#define BM_PRE_CTRL_RSVD2 0x0FFF0000
|
||||
#define BF_PRE_CTRL_RSVD2(v) \
|
||||
(((v) << 16) & BM_PRE_CTRL_RSVD2)
|
||||
#define BP_PRE_CTRL_RSVD1 12
|
||||
#define BM_PRE_CTRL_RSVD1 0x0000F000
|
||||
#define BF_PRE_CTRL_RSVD1(v) \
|
||||
(((v) << 12) & BM_PRE_CTRL_RSVD1)
|
||||
#define BM_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN 0x00000800
|
||||
#define BF_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN(v) \
|
||||
(((v) << 11) & BM_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN)
|
||||
#define BV_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN__0 0x0
|
||||
#define BV_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN__1 0x1
|
||||
#define BP_PRE_CTRL_HANDSHAKE_LINE_NUM 9
|
||||
#define BM_PRE_CTRL_HANDSHAKE_LINE_NUM 0x00000600
|
||||
#define BF_PRE_CTRL_HANDSHAKE_LINE_NUM(v) \
|
||||
(((v) << 9) & BM_PRE_CTRL_HANDSHAKE_LINE_NUM)
|
||||
#define BV_PRE_CTRL_HANDSHAKE_LINE_NUM__0 0x0
|
||||
#define BV_PRE_CTRL_HANDSHAKE_LINE_NUM__1 0x1
|
||||
#define BV_PRE_CTRL_HANDSHAKE_LINE_NUM__2 0x2
|
||||
#define BM_PRE_CTRL_HANDSHAKE_EN 0x00000100
|
||||
#define BF_PRE_CTRL_HANDSHAKE_EN(v) \
|
||||
(((v) << 8) & BM_PRE_CTRL_HANDSHAKE_EN)
|
||||
#define BV_PRE_CTRL_HANDSHAKE_EN__0 0x0
|
||||
#define BV_PRE_CTRL_HANDSHAKE_EN__1 0x1
|
||||
#define BM_PRE_CTRL_INTERLACED_FIELD 0x00000080
|
||||
#define BF_PRE_CTRL_INTERLACED_FIELD(v) \
|
||||
(((v) << 7) & BM_PRE_CTRL_INTERLACED_FIELD)
|
||||
#define BM_PRE_CTRL_SO 0x00000040
|
||||
#define BF_PRE_CTRL_SO(v) \
|
||||
(((v) << 6) & BM_PRE_CTRL_SO)
|
||||
#define BM_PRE_CTRL_VFLIP 0x00000020
|
||||
#define BF_PRE_CTRL_VFLIP(v) \
|
||||
(((v) << 5) & BM_PRE_CTRL_VFLIP)
|
||||
#define BM_PRE_CTRL_SDW_UPDATE 0x00000010
|
||||
#define BF_PRE_CTRL_SDW_UPDATE(v) \
|
||||
(((v) << 4) & BM_PRE_CTRL_SDW_UPDATE)
|
||||
#define BM_PRE_CTRL_RSVD0 0x00000008
|
||||
#define BF_PRE_CTRL_RSVD0(v) \
|
||||
(((v) << 3) & BM_PRE_CTRL_RSVD0)
|
||||
#define BM_PRE_CTRL_BLOCK_16 0x00000004
|
||||
#define BF_PRE_CTRL_BLOCK_16(v) \
|
||||
(((v) << 2) & BM_PRE_CTRL_BLOCK_16)
|
||||
#define BV_PRE_CTRL_BLOCK_16__32x4 0x0
|
||||
#define BV_PRE_CTRL_BLOCK_16__16x4 0x1
|
||||
#define BM_PRE_CTRL_BLOCK_EN 0x00000002
|
||||
#define BF_PRE_CTRL_BLOCK_EN(v) \
|
||||
(((v) << 1) & BM_PRE_CTRL_BLOCK_EN)
|
||||
#define BV_PRE_CTRL_BLOCK_EN__0 0x0
|
||||
#define BV_PRE_CTRL_BLOCK_EN__1 0x1
|
||||
#define BM_PRE_CTRL_ENABLE 0x00000001
|
||||
#define BF_PRE_CTRL_ENABLE(v) \
|
||||
(((v) << 0) & BM_PRE_CTRL_ENABLE)
|
||||
|
||||
#define HW_PRE_IRQ_MASK (0x00000010)
|
||||
#define HW_PRE_IRQ_MASK_SET (0x00000014)
|
||||
#define HW_PRE_IRQ_MASK_CLR (0x00000018)
|
||||
#define HW_PRE_IRQ_MASK_TOG (0x0000001c)
|
||||
|
||||
#define BP_PRE_IRQ_MASK_RSVD1 4
|
||||
#define BM_PRE_IRQ_MASK_RSVD1 0xFFFFFFF0
|
||||
#define BF_PRE_IRQ_MASK_RSVD1(v) \
|
||||
(((v) << 4) & BM_PRE_IRQ_MASK_RSVD1)
|
||||
#define BM_PRE_IRQ_MASK_TPR_RD_NUM_BYTES_OVFL_IRQ_EN 0x00000008
|
||||
#define BF_PRE_IRQ_MASK_TPR_RD_NUM_BYTES_OVFL_IRQ_EN(v) \
|
||||
(((v) << 3) & BM_PRE_IRQ_MASK_TPR_RD_NUM_BYTES_OVFL_IRQ_EN)
|
||||
#define BM_PRE_IRQ_MASK_HANDSHAKE_ABORT_IRQ_EN 0x00000004
|
||||
#define BF_PRE_IRQ_MASK_HANDSHAKE_ABORT_IRQ_EN(v) \
|
||||
(((v) << 2) & BM_PRE_IRQ_MASK_HANDSHAKE_ABORT_IRQ_EN)
|
||||
#define BM_PRE_IRQ_MASK_STORE_IRQ_EN 0x00000002
|
||||
#define BF_PRE_IRQ_MASK_STORE_IRQ_EN(v) \
|
||||
(((v) << 1) & BM_PRE_IRQ_MASK_STORE_IRQ_EN)
|
||||
#define BM_PRE_IRQ_MASK_PREFETCH_IRQ_EN 0x00000001
|
||||
#define BF_PRE_IRQ_MASK_PREFETCH_IRQ_EN(v) \
|
||||
(((v) << 0) & BM_PRE_IRQ_MASK_PREFETCH_IRQ_EN)
|
||||
|
||||
#define HW_PRE_IRQ (0x00000020)
|
||||
#define HW_PRE_IRQ_SET (0x00000024)
|
||||
#define HW_PRE_IRQ_CLR (0x00000028)
|
||||
#define HW_PRE_IRQ_TOG (0x0000002c)
|
||||
|
||||
#define BP_PRE_IRQ_RSVD1 14
|
||||
#define BM_PRE_IRQ_RSVD1 0xFFFFC000
|
||||
#define BF_PRE_IRQ_RSVD1(v) \
|
||||
(((v) << 14) & BM_PRE_IRQ_RSVD1)
|
||||
#define BP_PRE_IRQ_AXI_ERROR_ID 10
|
||||
#define BM_PRE_IRQ_AXI_ERROR_ID 0x00003C00
|
||||
#define BF_PRE_IRQ_AXI_ERROR_ID(v) \
|
||||
(((v) << 10) & BM_PRE_IRQ_AXI_ERROR_ID)
|
||||
#define BM_PRE_IRQ_AXI_READ_ERROR 0x00000200
|
||||
#define BF_PRE_IRQ_AXI_READ_ERROR(v) \
|
||||
(((v) << 9) & BM_PRE_IRQ_AXI_READ_ERROR)
|
||||
#define BM_PRE_IRQ_AXI_WRITE_ERROR 0x00000100
|
||||
#define BF_PRE_IRQ_AXI_WRITE_ERROR(v) \
|
||||
(((v) << 8) & BM_PRE_IRQ_AXI_WRITE_ERROR)
|
||||
#define BP_PRE_IRQ_RSVD0 5
|
||||
#define BM_PRE_IRQ_RSVD0 0x000000E0
|
||||
#define BF_PRE_IRQ_RSVD0(v) \
|
||||
(((v) << 5) & BM_PRE_IRQ_RSVD0)
|
||||
#define BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ 0x00000010
|
||||
#define BF_PRE_IRQ_HANDSHAKE_ERROR_IRQ(v) \
|
||||
(((v) << 4) & BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ)
|
||||
#define BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ 0x00000008
|
||||
#define BF_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ(v) \
|
||||
(((v) << 3) & BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ)
|
||||
#define BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ 0x00000004
|
||||
#define BF_PRE_IRQ_HANDSHAKE_ABORT_IRQ(v) \
|
||||
(((v) << 2) & BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ)
|
||||
#define BM_PRE_IRQ_STORE_IRQ 0x00000002
|
||||
#define BF_PRE_IRQ_STORE_IRQ(v) \
|
||||
(((v) << 1) & BM_PRE_IRQ_STORE_IRQ)
|
||||
#define BM_PRE_IRQ_PREFETCH_IRQ 0x00000001
|
||||
#define BF_PRE_IRQ_PREFETCH_IRQ(v) \
|
||||
(((v) << 0) & BM_PRE_IRQ_PREFETCH_IRQ)
|
||||
|
||||
#define HW_PRE_CUR_BUF (0x00000030)
|
||||
|
||||
#define BP_PRE_CUR_BUF_ADDR 0
|
||||
#define BM_PRE_CUR_BUF_ADDR 0xFFFFFFFF
|
||||
#define BF_PRE_CUR_BUF_ADDR(v) (v)
|
||||
|
||||
#define HW_PRE_NEXT_BUF (0x00000040)
|
||||
|
||||
#define BP_PRE_NEXT_BUF_ADDR 0
|
||||
#define BM_PRE_NEXT_BUF_ADDR 0xFFFFFFFF
|
||||
#define BF_PRE_NEXT_BUF_ADDR(v) (v)
|
||||
|
||||
#define HW_PRE_U_BUF_OFFSET (0x00000050)
|
||||
|
||||
#define BP_PRE_U_BUF_OFFSET_RSVD0 25
|
||||
#define BM_PRE_U_BUF_OFFSET_RSVD0 0xFE000000
|
||||
#define BF_PRE_U_BUF_OFFSET_RSVD0(v) \
|
||||
(((v) << 25) & BM_PRE_U_BUF_OFFSET_RSVD0)
|
||||
#define BP_PRE_U_BUF_OFFSET_UBO 0
|
||||
#define BM_PRE_U_BUF_OFFSET_UBO 0x01FFFFFF
|
||||
#define BF_PRE_U_BUF_OFFSET_UBO(v) \
|
||||
(((v) << 0) & BM_PRE_U_BUF_OFFSET_UBO)
|
||||
|
||||
#define HW_PRE_V_BUF_OFFSET (0x00000060)
|
||||
|
||||
#define BP_PRE_V_BUF_OFFSET_RSVD0 25
|
||||
#define BM_PRE_V_BUF_OFFSET_RSVD0 0xFE000000
|
||||
#define BF_PRE_V_BUF_OFFSET_RSVD0(v) \
|
||||
(((v) << 25) & BM_PRE_V_BUF_OFFSET_RSVD0)
|
||||
#define BP_PRE_V_BUF_OFFSET_VBO 0
|
||||
#define BM_PRE_V_BUF_OFFSET_VBO 0x01FFFFFF
|
||||
#define BF_PRE_V_BUF_OFFSET_VBO(v) \
|
||||
(((v) << 0) & BM_PRE_V_BUF_OFFSET_VBO)
|
||||
|
||||
#define HW_PRE_TPR_CTRL (0x00000070)
|
||||
#define HW_PRE_TPR_CTRL_SET (0x00000074)
|
||||
#define HW_PRE_TPR_CTRL_CLR (0x00000078)
|
||||
#define HW_PRE_TPR_CTRL_TOG (0x0000007c)
|
||||
|
||||
#define BP_PRE_TPR_CTRL_RSVD 8
|
||||
#define BM_PRE_TPR_CTRL_RSVD 0xFFFFFF00
|
||||
#define BF_PRE_TPR_CTRL_RSVD(v) \
|
||||
(((v) << 8) & BM_PRE_TPR_CTRL_RSVD)
|
||||
#define BP_PRE_TPR_CTRL_TILE_FORMAT 0
|
||||
#define BM_PRE_TPR_CTRL_TILE_FORMAT 0x000000FF
|
||||
#define BF_PRE_TPR_CTRL_TILE_FORMAT(v) \
|
||||
(((v) << 0) & BM_PRE_TPR_CTRL_TILE_FORMAT)
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__BYPASS 0x00
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_SB_ST 0x10
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_SB_SRT 0x50
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_ST 0x20
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_SRT 0x60
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_MST 0xA0
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU32_MSRT 0xE0
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_SB_ST 0x11
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_SB_SRT 0x51
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_ST 0x21
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_SRT 0x61
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_MST 0xA1
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__GPU16_MSRT 0xE1
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__VPU8_PRO 0x22
|
||||
#define BV_PRE_TPR_CTRL_TILE_FORMAT__VPU8_SB_INT 0x13
|
||||
|
||||
#define HW_PRE_PREFETCH_ENGINE_CTRL (0x00000080)
|
||||
#define HW_PRE_PREFETCH_ENGINE_CTRL_SET (0x00000084)
|
||||
#define HW_PRE_PREFETCH_ENGINE_CTRL_CLR (0x00000088)
|
||||
#define HW_PRE_PREFETCH_ENGINE_CTRL_TOG (0x0000008c)
|
||||
|
||||
#define BP_PRE_PREFETCH_ENGINE_CTRL_RSVD1 16
|
||||
#define BM_PRE_PREFETCH_ENGINE_CTRL_RSVD1 0xFFFF0000
|
||||
#define BF_PRE_PREFETCH_ENGINE_CTRL_RSVD1(v) \
|
||||
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_CTRL_RSVD1)
|
||||
#define BM_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN 0x00008000
|
||||
#define BF_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN(v) \
|
||||
(((v) << 15) & BM_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN)
|
||||
#define BM_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP 0x00004000
|
||||
#define BF_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP(v) \
|
||||
(((v) << 14) & BM_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP)
|
||||
#define BM_PRE_PREFETCH_ENGINE_CTRL_CROP_EN 0x00002000
|
||||
#define BF_PRE_PREFETCH_ENGINE_CTRL_CROP_EN(v) \
|
||||
(((v) << 13) & BM_PRE_PREFETCH_ENGINE_CTRL_CROP_EN)
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_CROP_EN__0 0x0
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_CROP_EN__1 0x1
|
||||
#define BM_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE 0x00001000
|
||||
#define BF_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE(v) \
|
||||
(((v) << 12) & BM_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE)
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE__0 0x0
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE__1 0x1
|
||||
#define BM_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS 0x00000800
|
||||
#define BF_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS(v) \
|
||||
(((v) << 11) & BM_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS)
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS__0 0x0
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS__1 0x1
|
||||
#define BP_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT 8
|
||||
#define BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT 0x00000700
|
||||
#define BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(v) \
|
||||
(((v) << 8) & BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT)
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__0 0x0
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__1 0x1
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__2 0x2
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__3 0x3
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__4 0x4
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT__5 0x5
|
||||
#define BP_PRE_PREFETCH_ENGINE_CTRL_RSVD0 6
|
||||
#define BM_PRE_PREFETCH_ENGINE_CTRL_RSVD0 0x000000C0
|
||||
#define BF_PRE_PREFETCH_ENGINE_CTRL_RSVD0(v) \
|
||||
(((v) << 6) & BM_PRE_PREFETCH_ENGINE_CTRL_RSVD0)
|
||||
#define BP_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP 4
|
||||
#define BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP 0x00000030
|
||||
#define BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(v) \
|
||||
(((v) << 4) & BM_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP)
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__0 0x0
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__1 0x1
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__2 0x2
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP__3 0x3
|
||||
#define BP_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES 1
|
||||
#define BM_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES 0x0000000E
|
||||
#define BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(v) \
|
||||
(((v) << 1) & BM_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES)
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__8_bytes 0x0
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__16_bytes 0x1
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__32_bytes 0x2
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__64_bytes 0x3
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES__128_bytes 0x4
|
||||
#define BM_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN 0x00000001
|
||||
#define BF_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN(v) \
|
||||
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN)
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN__0 0x0
|
||||
#define BV_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN__1 0x1
|
||||
|
||||
#define HW_PRE_PREFETCH_ENGINE_STATUS (0x00000090)
|
||||
|
||||
#define BP_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y 16
|
||||
#define BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y 0x3FFF0000
|
||||
#define BF_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y(v) \
|
||||
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_Y)
|
||||
#define BP_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X 0
|
||||
#define BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X 0x0000FFFF
|
||||
#define BF_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X(v) \
|
||||
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_STATUS_PREFETCH_BLOCK_X)
|
||||
|
||||
#define HW_PRE_PREFETCH_ENGINE_INPUT_SIZE (0x000000a0)
|
||||
|
||||
#define BP_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT 16
|
||||
#define BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT 0xFFFF0000
|
||||
#define BF_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT(v) \
|
||||
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT)
|
||||
#define BP_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH 0
|
||||
#define BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH 0x0000FFFF
|
||||
#define BF_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH(v) \
|
||||
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH)
|
||||
|
||||
#define HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC (0x000000b0)
|
||||
|
||||
#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y 16
|
||||
#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y 0xFFFF0000
|
||||
#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y(v) \
|
||||
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y)
|
||||
#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X 0
|
||||
#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X 0x0000FFFF
|
||||
#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X(v) \
|
||||
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X)
|
||||
|
||||
#define HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC (0x000000c0)
|
||||
|
||||
#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y 16
|
||||
#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y 0xFFFF0000
|
||||
#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y(v) \
|
||||
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_Y)
|
||||
#define BP_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X 0
|
||||
#define BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X 0x0000FFFF
|
||||
#define BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X(v) \
|
||||
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_LRC_OUTPUT_SIZE_LRC_X)
|
||||
|
||||
#define HW_PRE_PREFETCH_ENGINE_PITCH (0x000000d0)
|
||||
|
||||
#define BP_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH 16
|
||||
#define BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH 0xFFFF0000
|
||||
#define BF_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH(v) \
|
||||
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH)
|
||||
#define BP_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH 0
|
||||
#define BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH 0x0000FFFF
|
||||
#define BF_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH(v) \
|
||||
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH)
|
||||
|
||||
#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET (0x000000e0)
|
||||
#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_SET (0x000000e4)
|
||||
#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_CLR (0x000000e8)
|
||||
#define HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_TOG (0x000000ec)
|
||||
|
||||
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0 29
|
||||
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0 0xE0000000
|
||||
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0(v) \
|
||||
(((v) << 29) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD0)
|
||||
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3 24
|
||||
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3 0x1F000000
|
||||
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3(v) \
|
||||
(((v) << 24) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET3)
|
||||
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1 21
|
||||
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1 0x00E00000
|
||||
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1(v) \
|
||||
(((v) << 21) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD1)
|
||||
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2 16
|
||||
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2 0x001F0000
|
||||
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2(v) \
|
||||
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET2)
|
||||
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2 13
|
||||
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2 0x0000E000
|
||||
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2(v) \
|
||||
(((v) << 13) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD2)
|
||||
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1 8
|
||||
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1 0x00001F00
|
||||
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1(v) \
|
||||
(((v) << 8) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET1)
|
||||
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3 5
|
||||
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3 0x000000E0
|
||||
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3(v) \
|
||||
(((v) << 5) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_RSVD3)
|
||||
#define BP_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0 0
|
||||
#define BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0 0x0000001F
|
||||
#define BF_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0(v) \
|
||||
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_SHIFT_OFFSET_OFFSET0)
|
||||
|
||||
#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH (0x000000f0)
|
||||
#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_SET (0x000000f4)
|
||||
#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_CLR (0x000000f8)
|
||||
#define HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_TOG (0x000000fc)
|
||||
|
||||
#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0 16
|
||||
#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0 0xFFFF0000
|
||||
#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0(v) \
|
||||
(((v) << 16) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_RSVD0)
|
||||
#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3 12
|
||||
#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3 0x0000F000
|
||||
#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3(v) \
|
||||
(((v) << 12) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH3)
|
||||
#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2 8
|
||||
#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2 0x00000F00
|
||||
#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2(v) \
|
||||
(((v) << 8) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH2)
|
||||
#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1 4
|
||||
#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1 0x000000F0
|
||||
#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1(v) \
|
||||
(((v) << 4) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH1)
|
||||
#define BP_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0 0
|
||||
#define BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0 0x0000000F
|
||||
#define BF_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0(v) \
|
||||
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_SHIFT_WIDTH_WIDTH0)
|
||||
|
||||
#define HW_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET (0x00000100)
|
||||
|
||||
#define BP_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0 23
|
||||
#define BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0 0xFF800000
|
||||
#define BF_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0(v) \
|
||||
(((v) << 23) & BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_RSVD0)
|
||||
#define BP_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET 0
|
||||
#define BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET 0xFFFFFFFF
|
||||
#define BF_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET(v) \
|
||||
(((v) << 0) & BM_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET)
|
||||
|
||||
#define HW_PRE_STORE_ENGINE_CTRL (0x00000110)
|
||||
#define HW_PRE_STORE_ENGINE_CTRL_SET (0x00000114)
|
||||
#define HW_PRE_STORE_ENGINE_CTRL_CLR (0x00000118)
|
||||
#define HW_PRE_STORE_ENGINE_CTRL_TOG (0x0000011c)
|
||||
|
||||
#define BP_PRE_STORE_ENGINE_CTRL_RSVD0 6
|
||||
#define BM_PRE_STORE_ENGINE_CTRL_RSVD0 0xFFFFFFC0
|
||||
#define BF_PRE_STORE_ENGINE_CTRL_RSVD0(v) \
|
||||
(((v) << 6) & BM_PRE_STORE_ENGINE_CTRL_RSVD0)
|
||||
#define BP_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP 4
|
||||
#define BM_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP 0x00000030
|
||||
#define BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(v) \
|
||||
(((v) << 4) & BM_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP)
|
||||
#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__8_bits 0x0
|
||||
#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__16_bits 0x1
|
||||
#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__32_bits 0x2
|
||||
#define BV_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP__64_bits 0x3
|
||||
#define BP_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES 1
|
||||
#define BM_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES 0x0000000E
|
||||
#define BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(v) \
|
||||
(((v) << 1) & BM_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES)
|
||||
#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__8_bytes 0x0
|
||||
#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__16_bytes 0x1
|
||||
#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__32_bytes 0x2
|
||||
#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__64_bytes 0x3
|
||||
#define BV_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES__128_bytes 0x4
|
||||
#define BM_PRE_STORE_ENGINE_CTRL_STORE_EN 0x00000001
|
||||
#define BF_PRE_STORE_ENGINE_CTRL_STORE_EN(v) \
|
||||
(((v) << 0) & BM_PRE_STORE_ENGINE_CTRL_STORE_EN)
|
||||
#define BV_PRE_STORE_ENGINE_CTRL_STORE_EN__0 0x0
|
||||
#define BV_PRE_STORE_ENGINE_CTRL_STORE_EN__1 0x1
|
||||
|
||||
#define HW_PRE_STORE_ENGINE_STATUS (0x00000120)
|
||||
|
||||
#define BP_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y 16
|
||||
#define BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y 0x3FFF0000
|
||||
#define BF_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y(v) \
|
||||
(((v) << 16) & BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_Y)
|
||||
#define BP_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X 0
|
||||
#define BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X 0x0000FFFF
|
||||
#define BF_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X(v) \
|
||||
(((v) << 0) & BM_PRE_STORE_ENGINE_STATUS_STORE_BLOCK_X)
|
||||
|
||||
#define HW_PRE_STORE_ENGINE_SIZE (0x00000130)
|
||||
|
||||
#define BP_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT 16
|
||||
#define BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT 0xFFFF0000
|
||||
#define BF_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT(v) \
|
||||
(((v) << 16) & BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT)
|
||||
#define BP_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH 0
|
||||
#define BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH 0x0000FFFF
|
||||
#define BF_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH(v) \
|
||||
(((v) << 0) & BM_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH)
|
||||
|
||||
#define HW_PRE_STORE_ENGINE_PITCH (0x00000140)
|
||||
|
||||
#define BP_PRE_STORE_ENGINE_PITCH_RSVD0 16
|
||||
#define BM_PRE_STORE_ENGINE_PITCH_RSVD0 0xFFFF0000
|
||||
#define BF_PRE_STORE_ENGINE_PITCH_RSVD0(v) \
|
||||
(((v) << 16) & BM_PRE_STORE_ENGINE_PITCH_RSVD0)
|
||||
#define BP_PRE_STORE_ENGINE_PITCH_OUT_PITCH 0
|
||||
#define BM_PRE_STORE_ENGINE_PITCH_OUT_PITCH 0x0000FFFF
|
||||
#define BF_PRE_STORE_ENGINE_PITCH_OUT_PITCH(v) \
|
||||
(((v) << 0) & BM_PRE_STORE_ENGINE_PITCH_OUT_PITCH)
|
||||
|
||||
#define HW_PRE_STORE_ENGINE_ADDR (0x00000150)
|
||||
|
||||
#define BP_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR 0
|
||||
#define BM_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR 0xFFFFFFFF
|
||||
#define BF_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR(v) (v)
|
||||
#endif /* __ARCH_ARM___PRE_H */
|
|
@ -0,0 +1,973 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ipu-v3.h>
|
||||
#include <linux/ipu-v3-pre.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "pre-regs.h"
|
||||
|
||||
struct ipu_pre_data {
|
||||
unsigned int id;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
|
||||
struct mutex mutex; /* for in_use */
|
||||
spinlock_t lock; /* for register access */
|
||||
|
||||
struct list_head list;
|
||||
|
||||
struct gen_pool *iram_pool;
|
||||
unsigned long double_buffer_size;
|
||||
unsigned long double_buffer_base;
|
||||
unsigned long double_buffer_paddr;
|
||||
|
||||
bool in_use;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
static LIST_HEAD(pre_list);
|
||||
static DEFINE_MUTEX(pre_list_lock);
|
||||
|
||||
static inline void pre_write(struct ipu_pre_data *pre,
|
||||
u32 value, unsigned int offset)
|
||||
{
|
||||
writel(value, pre->base + offset);
|
||||
}
|
||||
|
||||
static inline u32 pre_read(struct ipu_pre_data *pre, unsigned offset)
|
||||
{
|
||||
return readl(pre->base + offset);
|
||||
}
|
||||
|
||||
static struct ipu_pre_data *get_pre(unsigned int id)
|
||||
{
|
||||
struct ipu_pre_data *pre;
|
||||
|
||||
mutex_lock(&pre_list_lock);
|
||||
list_for_each_entry(pre, &pre_list, list) {
|
||||
if (pre->id == id) {
|
||||
mutex_unlock(&pre_list_lock);
|
||||
return pre;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&pre_list_lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ipu_pre_alloc(int ipu_id, ipu_channel_t channel)
|
||||
{
|
||||
struct ipu_pre_data *pre;
|
||||
int i, fixed;
|
||||
|
||||
if (channel == MEM_BG_SYNC) {
|
||||
fixed = ipu_id ? 3 : 0;
|
||||
pre = get_pre(fixed);
|
||||
if (pre) {
|
||||
mutex_lock(&pre->mutex);
|
||||
if (!pre->in_use) {
|
||||
pre->in_use = true;
|
||||
mutex_unlock(&pre->mutex);
|
||||
return pre->id;
|
||||
}
|
||||
mutex_unlock(&pre->mutex);
|
||||
}
|
||||
return pre ? -EBUSY : -ENOENT;
|
||||
}
|
||||
|
||||
for (i = 1; i < 3; i++) {
|
||||
pre = get_pre(i);
|
||||
if (!pre)
|
||||
continue;
|
||||
mutex_lock(&pre->mutex);
|
||||
if (!pre->in_use) {
|
||||
pre->in_use = true;
|
||||
mutex_unlock(&pre->mutex);
|
||||
return pre->id;
|
||||
}
|
||||
mutex_unlock(&pre->mutex);
|
||||
}
|
||||
|
||||
return pre ? -EBUSY : -ENOENT;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_pre_alloc);
|
||||
|
||||
void ipu_pre_free(unsigned int *id)
|
||||
{
|
||||
struct ipu_pre_data *pre;
|
||||
|
||||
pre = get_pre(*id);
|
||||
if (!pre)
|
||||
return;
|
||||
|
||||
mutex_lock(&pre->mutex);
|
||||
pre->in_use = false;
|
||||
mutex_unlock(&pre->mutex);
|
||||
|
||||
*id = -1;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_pre_free);
|
||||
|
||||
unsigned long ipu_pre_alloc_double_buffer(unsigned int id, unsigned int size)
|
||||
{
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
|
||||
if (!pre)
|
||||
return -ENOENT;
|
||||
|
||||
if (!size)
|
||||
return -EINVAL;
|
||||
|
||||
pre->double_buffer_base = gen_pool_alloc(pre->iram_pool, size);
|
||||
if (!pre->double_buffer_base) {
|
||||
dev_err(pre->dev, "double buffer allocate failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
pre->double_buffer_size = size;
|
||||
|
||||
pre->double_buffer_paddr = gen_pool_virt_to_phys(pre->iram_pool,
|
||||
pre->double_buffer_base);
|
||||
|
||||
return pre->double_buffer_paddr;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_pre_alloc_double_buffer);
|
||||
|
||||
void ipu_pre_free_double_buffer(unsigned int id)
|
||||
{
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
|
||||
if (!pre)
|
||||
return;
|
||||
|
||||
if (pre->double_buffer_base) {
|
||||
gen_pool_free(pre->iram_pool,
|
||||
pre->double_buffer_base,
|
||||
pre->double_buffer_size);
|
||||
pre->double_buffer_base = 0;
|
||||
pre->double_buffer_size = 0;
|
||||
pre->double_buffer_paddr = 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_pre_free_double_buffer);
|
||||
|
||||
/* PRE register configurations */
|
||||
static int ipu_pre_set_ctrl(unsigned int id,
|
||||
bool repeat,
|
||||
bool vflip,
|
||||
bool handshake_en,
|
||||
bool hsk_abort_en,
|
||||
unsigned int hsk_line_num,
|
||||
bool sdw_update,
|
||||
unsigned int block_size,
|
||||
unsigned int interlaced,
|
||||
unsigned int prefetch_mode)
|
||||
{
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
unsigned long lock_flags;
|
||||
int ret = 0;
|
||||
|
||||
if (!pre)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&pre->lock, lock_flags);
|
||||
pre_write(pre, BF_PRE_CTRL_TPR_RESET_SEL(1), HW_PRE_CTRL_SET);
|
||||
|
||||
if (repeat)
|
||||
pre_write(pre, BF_PRE_CTRL_EN_REPEAT(1), HW_PRE_CTRL_SET);
|
||||
else
|
||||
pre_write(pre, BM_PRE_CTRL_EN_REPEAT, HW_PRE_CTRL_CLR);
|
||||
|
||||
if (vflip)
|
||||
pre_write(pre, BF_PRE_CTRL_VFLIP(1), HW_PRE_CTRL_SET);
|
||||
else
|
||||
pre_write(pre, BM_PRE_CTRL_VFLIP, HW_PRE_CTRL_CLR);
|
||||
|
||||
if (handshake_en) {
|
||||
pre_write(pre, BF_PRE_CTRL_HANDSHAKE_EN(1), HW_PRE_CTRL_SET);
|
||||
if (hsk_abort_en)
|
||||
pre_write(pre, BF_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN(1),
|
||||
HW_PRE_CTRL_SET);
|
||||
else
|
||||
pre_write(pre, BM_PRE_CTRL_HANDSHAKE_ABORT_SKIP_EN,
|
||||
HW_PRE_CTRL_CLR);
|
||||
|
||||
switch (hsk_line_num) {
|
||||
case 0 /* 4 lines */:
|
||||
pre_write(pre, BM_PRE_CTRL_HANDSHAKE_LINE_NUM,
|
||||
HW_PRE_CTRL_CLR);
|
||||
break;
|
||||
case 1 /* 8 lines */:
|
||||
pre_write(pre, BM_PRE_CTRL_HANDSHAKE_LINE_NUM,
|
||||
HW_PRE_CTRL_CLR);
|
||||
pre_write(pre, BF_PRE_CTRL_HANDSHAKE_LINE_NUM(1),
|
||||
HW_PRE_CTRL_SET);
|
||||
break;
|
||||
case 2 /* 16 lines */:
|
||||
pre_write(pre, BM_PRE_CTRL_HANDSHAKE_LINE_NUM,
|
||||
HW_PRE_CTRL_CLR);
|
||||
pre_write(pre, BF_PRE_CTRL_HANDSHAKE_LINE_NUM(2),
|
||||
HW_PRE_CTRL_SET);
|
||||
break;
|
||||
default:
|
||||
dev_err(pre->dev, "invalid hanshake line number\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
} else
|
||||
pre_write(pre, BM_PRE_CTRL_HANDSHAKE_EN, HW_PRE_CTRL_CLR);
|
||||
|
||||
|
||||
switch (prefetch_mode) {
|
||||
case 0:
|
||||
pre_write(pre, BM_PRE_CTRL_BLOCK_EN, HW_PRE_CTRL_CLR);
|
||||
break;
|
||||
case 1:
|
||||
pre_write(pre, BF_PRE_CTRL_BLOCK_EN(1), HW_PRE_CTRL_SET);
|
||||
switch (block_size) {
|
||||
case 0:
|
||||
pre_write(pre, BM_PRE_CTRL_BLOCK_16, HW_PRE_CTRL_CLR);
|
||||
break;
|
||||
case 1:
|
||||
pre_write(pre, BF_PRE_CTRL_BLOCK_16(1), HW_PRE_CTRL_SET);
|
||||
break;
|
||||
default:
|
||||
dev_err(pre->dev, "invalid block size for pre\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_err(pre->dev, "invalid prefech mode for pre\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (interlaced) {
|
||||
case 0: /* progressive mode */
|
||||
pre_write(pre, BM_PRE_CTRL_SO, HW_PRE_CTRL_CLR);
|
||||
break;
|
||||
case 2: /* interlaced mode: Pal */
|
||||
pre_write(pre, BF_PRE_CTRL_SO(1), HW_PRE_CTRL_SET);
|
||||
pre_write(pre, BM_PRE_CTRL_INTERLACED_FIELD, HW_PRE_CTRL_CLR);
|
||||
break;
|
||||
case 3: /* interlaced mode: NTSC */
|
||||
pre_write(pre, BF_PRE_CTRL_SO(1), HW_PRE_CTRL_SET);
|
||||
pre_write(pre, BF_PRE_CTRL_INTERLACED_FIELD(1), HW_PRE_CTRL_SET);
|
||||
break;
|
||||
default:
|
||||
dev_err(pre->dev, "invalid interlaced or progressive mode\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (sdw_update)
|
||||
pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET);
|
||||
else
|
||||
pre_write(pre, BM_PRE_CTRL_SDW_UPDATE, HW_PRE_CTRL_CLR);
|
||||
|
||||
err:
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ipu_pre_irq_mask(struct ipu_pre_data *pre,
|
||||
unsigned long mask, bool clear)
|
||||
{
|
||||
if (clear) {
|
||||
pre_write(pre, mask & 0xf, HW_PRE_IRQ_MASK_CLR);
|
||||
return;
|
||||
}
|
||||
pre_write(pre, mask & 0xf, HW_PRE_IRQ_MASK_SET);
|
||||
}
|
||||
|
||||
static int ipu_pre_buf_set(unsigned int id, unsigned long cur_buf,
|
||||
unsigned long next_buf)
|
||||
{
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
unsigned long lock_flags;
|
||||
|
||||
if (!pre)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&pre->lock, lock_flags);
|
||||
pre_write(pre, cur_buf, HW_PRE_CUR_BUF);
|
||||
pre_write(pre, next_buf, HW_PRE_NEXT_BUF);
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipu_pre_plane_buf_off_set(unsigned int id,
|
||||
unsigned long sec_buf_off,
|
||||
unsigned long trd_buf_off)
|
||||
{
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
unsigned long lock_flags;
|
||||
|
||||
if (!pre || sec_buf_off & BM_PRE_U_BUF_OFFSET_RSVD0 ||
|
||||
trd_buf_off & BM_PRE_V_BUF_OFFSET_RSVD0)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&pre->lock, lock_flags);
|
||||
pre_write(pre, sec_buf_off, HW_PRE_U_BUF_OFFSET);
|
||||
pre_write(pre, trd_buf_off, HW_PRE_V_BUF_OFFSET);
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipu_pre_tpr_set(unsigned int id, unsigned int tile_fmt)
|
||||
{
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
unsigned long lock_flags;
|
||||
unsigned int tpr_ctrl, fmt;
|
||||
|
||||
if (!pre)
|
||||
return -EINVAL;
|
||||
|
||||
switch (tile_fmt) {
|
||||
case 0x0: /* Bypass */
|
||||
fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x0);
|
||||
break;
|
||||
case IPU_PIX_FMT_GPU32_SB_ST:
|
||||
fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x10);
|
||||
break;
|
||||
case IPU_PIX_FMT_GPU16_SB_ST:
|
||||
fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x11);
|
||||
break;
|
||||
case IPU_PIX_FMT_GPU32_ST:
|
||||
fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x20);
|
||||
break;
|
||||
case IPU_PIX_FMT_GPU16_ST:
|
||||
fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x21);
|
||||
break;
|
||||
case IPU_PIX_FMT_GPU32_SB_SRT:
|
||||
fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x50);
|
||||
break;
|
||||
case IPU_PIX_FMT_GPU16_SB_SRT:
|
||||
fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x51);
|
||||
break;
|
||||
case IPU_PIX_FMT_GPU32_SRT:
|
||||
fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x60);
|
||||
break;
|
||||
case IPU_PIX_FMT_GPU16_SRT:
|
||||
fmt = BF_PRE_TPR_CTRL_TILE_FORMAT(0x61);
|
||||
break;
|
||||
default:
|
||||
dev_err(pre->dev, "invalid tile fmt for pre\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&pre->lock, lock_flags);
|
||||
tpr_ctrl = pre_read(pre, HW_PRE_TPR_CTRL);
|
||||
tpr_ctrl &= ~BM_PRE_TPR_CTRL_TILE_FORMAT;
|
||||
tpr_ctrl |= fmt;
|
||||
pre_write(pre, tpr_ctrl, HW_PRE_TPR_CTRL);
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipu_pre_set_shift(int id, unsigned int offset, unsigned int width)
|
||||
{
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
unsigned long lock_flags;
|
||||
|
||||
if (!pre)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&pre->lock, lock_flags);
|
||||
pre_write(pre, offset, HW_PRE_PREFETCH_ENGINE_SHIFT_OFFSET);
|
||||
pre_write(pre, width, HW_PRE_PREFETCH_ENGINE_SHIFT_WIDTH);
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipu_pre_prefetch(unsigned int id,
|
||||
unsigned int read_burst,
|
||||
unsigned int input_bpp,
|
||||
unsigned int input_pixel_fmt,
|
||||
bool shift_bypass,
|
||||
bool field_inverse,
|
||||
bool tpr_coor_offset_en,
|
||||
struct ipu_rect output_size,
|
||||
unsigned int input_width,
|
||||
unsigned int input_height,
|
||||
unsigned int input_active_width,
|
||||
unsigned int interlaced,
|
||||
int interlace_offset)
|
||||
{
|
||||
unsigned int prefetch_ctrl = 0;
|
||||
unsigned int input_y_pitch = 0, input_uv_pitch = 0;
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
unsigned long lock_flags;
|
||||
|
||||
if (!pre)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&pre->lock, lock_flags);
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_PREFETCH_EN(1);
|
||||
switch (read_burst) {
|
||||
case 0x0:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x0);
|
||||
break;
|
||||
case 0x1:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x1);
|
||||
break;
|
||||
case 0x2:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x2);
|
||||
break;
|
||||
case 0x3:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x3);
|
||||
break;
|
||||
case 0x4:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_RD_NUM_BYTES(0x4);
|
||||
break;
|
||||
default:
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
dev_err(pre->dev, "invalid read burst for prefetch engine\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (input_bpp) {
|
||||
case 8:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(0x0);
|
||||
break;
|
||||
case 16:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(0x1);
|
||||
break;
|
||||
case 32:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(0x2);
|
||||
break;
|
||||
case 64:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_ACTIVE_BPP(0x3);
|
||||
break;
|
||||
default:
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
dev_err(pre->dev, "invalid input bpp for prefetch engine\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (input_pixel_fmt) {
|
||||
case 0x1: /* tile */
|
||||
case 0x0: /* generic data */
|
||||
case IPU_PIX_FMT_RGB666:
|
||||
case IPU_PIX_FMT_RGB565:
|
||||
case IPU_PIX_FMT_BGRA4444:
|
||||
case IPU_PIX_FMT_BGRA5551:
|
||||
case IPU_PIX_FMT_BGR24:
|
||||
case IPU_PIX_FMT_RGB24:
|
||||
case IPU_PIX_FMT_GBR24:
|
||||
case IPU_PIX_FMT_BGR32:
|
||||
case IPU_PIX_FMT_BGRA32:
|
||||
case IPU_PIX_FMT_RGB32:
|
||||
case IPU_PIX_FMT_RGBA32:
|
||||
case IPU_PIX_FMT_ABGR32:
|
||||
case IPU_PIX_FMT_YUYV:
|
||||
case IPU_PIX_FMT_UYVY:
|
||||
case IPU_PIX_FMT_YUV444:
|
||||
case IPU_PIX_FMT_AYUV:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x0);
|
||||
input_y_pitch = input_width * (input_bpp >> 3);
|
||||
if (interlaced && input_pixel_fmt != 0x1)
|
||||
input_y_pitch *= 2;
|
||||
break;
|
||||
case IPU_PIX_FMT_YUV444P:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x1);
|
||||
input_y_pitch = input_width;
|
||||
input_uv_pitch = input_width;
|
||||
break;
|
||||
case IPU_PIX_FMT_YUV422P:
|
||||
case IPU_PIX_FMT_YVU422P:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x2);
|
||||
input_y_pitch = input_width;
|
||||
input_uv_pitch = input_width >> 1;
|
||||
break;
|
||||
case IPU_PIX_FMT_YUV420P2:
|
||||
case IPU_PIX_FMT_YUV420P:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x3);
|
||||
input_y_pitch = input_width;
|
||||
input_uv_pitch = input_width >> 1;
|
||||
break;
|
||||
case PRE_PIX_FMT_NV61:
|
||||
prefetch_ctrl |= BM_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP;
|
||||
case IPU_PIX_FMT_NV16:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x4);
|
||||
input_y_pitch = input_width;
|
||||
input_uv_pitch = input_width;
|
||||
break;
|
||||
case PRE_PIX_FMT_NV21:
|
||||
prefetch_ctrl |= BM_PRE_PREFETCH_ENGINE_CTRL_PARTIAL_UV_SWAP;
|
||||
case IPU_PIX_FMT_NV12:
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_INPUT_PIXEL_FORMAT(0x5);
|
||||
input_y_pitch = input_width;
|
||||
input_uv_pitch = input_width;
|
||||
break;
|
||||
default:
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
dev_err(pre->dev, "invalid input pixel format for prefetch engine\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_SHIFT_BYPASS(shift_bypass ? 1 : 0);
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_FIELD_INVERSE(field_inverse ? 1 : 0);
|
||||
prefetch_ctrl |= BF_PRE_PREFETCH_ENGINE_CTRL_TPR_COOR_OFFSET_EN(tpr_coor_offset_en ? 1 : 0);
|
||||
|
||||
pre_write(pre, BF_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_WIDTH(input_active_width) |
|
||||
BF_PRE_PREFETCH_ENGINE_INPUT_SIZE_INPUT_HEIGHT(input_height),
|
||||
HW_PRE_PREFETCH_ENGINE_INPUT_SIZE);
|
||||
|
||||
if (tpr_coor_offset_en)
|
||||
pre_write(pre, BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X(output_size.left) |
|
||||
BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y(output_size.top),
|
||||
HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC);
|
||||
|
||||
pre_write(pre, BF_PRE_PREFETCH_ENGINE_PITCH_INPUT_Y_PITCH(input_y_pitch) |
|
||||
BF_PRE_PREFETCH_ENGINE_PITCH_INPUT_UV_PITCH(input_uv_pitch),
|
||||
HW_PRE_PREFETCH_ENGINE_PITCH);
|
||||
|
||||
pre_write(pre, BF_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET_INTERLACE_OFFSET(interlace_offset), HW_PRE_PREFETCH_ENGINE_INTERLACE_OFFSET);
|
||||
|
||||
pre_write(pre, prefetch_ctrl, HW_PRE_PREFETCH_ENGINE_CTRL);
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipu_pre_store(unsigned int id,
|
||||
bool store_en,
|
||||
unsigned int write_burst,
|
||||
unsigned int output_bpp,
|
||||
/* this means the output
|
||||
* width by prefetch
|
||||
*/
|
||||
unsigned int input_width,
|
||||
unsigned int input_height,
|
||||
unsigned int out_pitch,
|
||||
unsigned int output_addr)
|
||||
{
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
unsigned int store_ctrl = 0;
|
||||
unsigned long lock_flags;
|
||||
|
||||
if (!pre)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&pre->lock, lock_flags);
|
||||
store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_STORE_EN(store_en ? 1 : 0);
|
||||
|
||||
if (store_en) {
|
||||
switch (write_burst) {
|
||||
case 0x0:
|
||||
store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x0);
|
||||
break;
|
||||
case 0x1:
|
||||
store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x1);
|
||||
break;
|
||||
case 0x2:
|
||||
store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x2);
|
||||
break;
|
||||
case 0x3:
|
||||
store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x3);
|
||||
break;
|
||||
case 0x4:
|
||||
store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_WR_NUM_BYTES(0x4);
|
||||
break;
|
||||
default:
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
dev_err(pre->dev, "invalid write burst value for store engine\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (output_bpp) {
|
||||
case 8:
|
||||
store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(0x0);
|
||||
break;
|
||||
case 16:
|
||||
store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(0x1);
|
||||
break;
|
||||
case 32:
|
||||
store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(0x2);
|
||||
break;
|
||||
case 64:
|
||||
store_ctrl |= BF_PRE_STORE_ENGINE_CTRL_OUTPUT_ACTIVE_BPP(0x3);
|
||||
break;
|
||||
default:
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
dev_err(pre->dev, "invalid ouput bpp for store engine\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pre_write(pre, BF_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_WIDTH(input_width) |
|
||||
BF_PRE_STORE_ENGINE_SIZE_INPUT_TOTAL_HEIGHT(input_height),
|
||||
HW_PRE_STORE_ENGINE_SIZE);
|
||||
|
||||
pre_write(pre, BF_PRE_STORE_ENGINE_PITCH_OUT_PITCH(out_pitch),
|
||||
HW_PRE_STORE_ENGINE_PITCH);
|
||||
|
||||
pre_write(pre, BF_PRE_STORE_ENGINE_ADDR_OUT_BASE_ADDR(output_addr),
|
||||
HW_PRE_STORE_ENGINE_ADDR);
|
||||
}
|
||||
|
||||
pre_write(pre, store_ctrl, HW_PRE_STORE_ENGINE_CTRL);
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* End */
|
||||
|
||||
static irqreturn_t ipu_pre_irq_handle(int irq, void *dev_id)
|
||||
{
|
||||
struct ipu_pre_data *pre = dev_id;
|
||||
unsigned int irq_stat, axi_id = 0;
|
||||
|
||||
spin_lock(&pre->lock);
|
||||
irq_stat = pre_read(pre, HW_PRE_IRQ);
|
||||
|
||||
if (irq_stat & BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ) {
|
||||
dev_warn(pre->dev, "handshake abort\n");
|
||||
pre_write(pre, BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ, HW_PRE_IRQ_CLR);
|
||||
}
|
||||
|
||||
if (irq_stat & BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ) {
|
||||
dev_warn(pre->dev, "tpr read num bytes overflow\n");
|
||||
pre_write(pre, BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ,
|
||||
HW_PRE_IRQ_CLR);
|
||||
}
|
||||
|
||||
if (irq_stat & BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ) {
|
||||
dev_warn(pre->dev, "handshake error\n");
|
||||
pre_write(pre, BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ, HW_PRE_IRQ_CLR);
|
||||
}
|
||||
|
||||
axi_id = (irq_stat & BM_PRE_IRQ_AXI_ERROR_ID) >>
|
||||
BP_PRE_IRQ_AXI_ERROR_ID;
|
||||
if (irq_stat & BM_PRE_IRQ_AXI_WRITE_ERROR) {
|
||||
dev_warn(pre->dev, "AXI%d write error\n", axi_id);
|
||||
pre_write(pre, BM_PRE_IRQ_AXI_WRITE_ERROR, HW_PRE_IRQ_CLR);
|
||||
}
|
||||
|
||||
if (irq_stat & BM_PRE_IRQ_AXI_READ_ERROR) {
|
||||
dev_warn(pre->dev, "AXI%d read error\n", axi_id);
|
||||
pre_write(pre, BM_PRE_IRQ_AXI_READ_ERROR, HW_PRE_IRQ_CLR);
|
||||
}
|
||||
spin_unlock(&pre->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void ipu_pre_out_of_reset(unsigned int id)
|
||||
{
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
unsigned long lock_flags;
|
||||
|
||||
if (!pre)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&pre->lock, lock_flags);
|
||||
pre_write(pre, BF_PRE_CTRL_SFTRST(1) | BF_PRE_CTRL_CLKGATE(1),
|
||||
HW_PRE_CTRL_CLR);
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
}
|
||||
|
||||
int ipu_pre_config(int id, struct ipu_pre_context *config)
|
||||
{
|
||||
int ret = 0;
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
|
||||
if (!config || !pre)
|
||||
return -EINVAL;
|
||||
|
||||
config->store_addr = pre->double_buffer_paddr;
|
||||
|
||||
if (!pre->enabled)
|
||||
clk_prepare_enable(pre->clk);
|
||||
|
||||
ipu_pre_out_of_reset(id);
|
||||
|
||||
ret = ipu_pre_plane_buf_off_set(id, config->sec_buf_off,
|
||||
config->trd_buf_off);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = ipu_pre_tpr_set(id, config->tile_fmt);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = ipu_pre_buf_set(id, config->cur_buf, config->next_buf);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = ipu_pre_set_shift(id, config->prefetch_shift_offset,
|
||||
config->prefetch_shift_width);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = ipu_pre_prefetch(id, config->read_burst, config->prefetch_input_bpp,
|
||||
config->prefetch_input_pixel_fmt, config->shift_bypass,
|
||||
config->field_inverse, config->tpr_coor_offset_en,
|
||||
config->prefetch_output_size, config->prefetch_input_width,
|
||||
config->prefetch_input_height,
|
||||
config->prefetch_input_active_width,
|
||||
config->interlaced,
|
||||
config->interlace_offset);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = ipu_pre_store(id, config->store_en,
|
||||
config->write_burst, config->store_output_bpp,
|
||||
config->prefetch_output_size.width, config->prefetch_output_size.height,
|
||||
config->store_pitch,
|
||||
config->store_addr);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = ipu_pre_set_ctrl(id, config->repeat,
|
||||
config->vflip, config->handshake_en,
|
||||
config->hsk_abort_en, config->hsk_line_num,
|
||||
config->sdw_update, config->block_size,
|
||||
config->interlaced, config->prefetch_mode);
|
||||
|
||||
ipu_pre_irq_mask(pre, BM_PRE_IRQ_HANDSHAKE_ABORT_IRQ |
|
||||
BM_PRE_IRQ_TPR_RD_NUM_BYTES_OVFL_IRQ |
|
||||
BM_PRE_IRQ_HANDSHAKE_ERROR_IRQ, false);
|
||||
out:
|
||||
if (!pre->enabled)
|
||||
clk_disable_unprepare(pre->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_pre_config);
|
||||
|
||||
int ipu_pre_enable(int id)
|
||||
{
|
||||
int ret = 0;
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
unsigned long lock_flags;
|
||||
|
||||
if (!pre)
|
||||
return -EINVAL;
|
||||
|
||||
if (pre->enabled)
|
||||
return 0;
|
||||
|
||||
clk_prepare_enable(pre->clk);
|
||||
|
||||
/* start the pre engine */
|
||||
spin_lock_irqsave(&pre->lock, lock_flags);
|
||||
pre_write(pre, BF_PRE_CTRL_ENABLE(1), HW_PRE_CTRL_SET);
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
|
||||
pre->enabled = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_pre_enable);
|
||||
|
||||
int ipu_pre_sdw_update(int id)
|
||||
{
|
||||
int ret = 0;
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
unsigned long lock_flags;
|
||||
|
||||
if (!pre)
|
||||
return -EINVAL;
|
||||
|
||||
if (!pre->enabled)
|
||||
clk_prepare_enable(pre->clk);
|
||||
|
||||
/* start the pre engine */
|
||||
spin_lock_irqsave(&pre->lock, lock_flags);
|
||||
pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET);
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
|
||||
if (!pre->enabled)
|
||||
clk_disable_unprepare(pre->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_pre_sdw_update);
|
||||
|
||||
void ipu_pre_disable(int id)
|
||||
{
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
unsigned long lock_flags;
|
||||
|
||||
if (!pre)
|
||||
return;
|
||||
|
||||
if (!pre->enabled)
|
||||
return;
|
||||
|
||||
/* stop the pre engine */
|
||||
spin_lock_irqsave(&pre->lock, lock_flags);
|
||||
pre_write(pre, BF_PRE_CTRL_ENABLE(1), HW_PRE_CTRL_CLR);
|
||||
pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET);
|
||||
pre_write(pre, BF_PRE_CTRL_SFTRST(1), HW_PRE_CTRL_SET);
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
|
||||
clk_disable_unprepare(pre->clk);
|
||||
|
||||
pre->enabled = false;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_pre_disable);
|
||||
|
||||
int ipu_pre_set_fb_buffer(int id, unsigned long fb_paddr,
|
||||
unsigned int x_crop,
|
||||
unsigned int y_crop,
|
||||
unsigned int sec_buf_off,
|
||||
unsigned int trd_buf_off)
|
||||
{
|
||||
struct ipu_pre_data *pre = get_pre(id);
|
||||
unsigned long lock_flags;
|
||||
|
||||
if (!pre)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&pre->lock, lock_flags);
|
||||
pre_write(pre, fb_paddr, HW_PRE_NEXT_BUF);
|
||||
pre_write(pre, sec_buf_off, HW_PRE_U_BUF_OFFSET);
|
||||
pre_write(pre, trd_buf_off, HW_PRE_V_BUF_OFFSET);
|
||||
pre_write(pre, BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_X(x_crop) |
|
||||
BF_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC_OUTPUT_SIZE_ULC_Y(y_crop),
|
||||
HW_PRE_PREFETCH_ENGINE_OUTPUT_SIZE_ULC);
|
||||
pre_write(pre, BF_PRE_CTRL_SDW_UPDATE(1), HW_PRE_CTRL_SET);
|
||||
spin_unlock_irqrestore(&pre->lock, lock_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_pre_set_fb_buffer);
|
||||
|
||||
static int ipu_pre_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct ipu_pre_data *pre;
|
||||
struct resource *res;
|
||||
int id, irq, err;
|
||||
|
||||
pre = devm_kzalloc(&pdev->dev, sizeof(*pre), GFP_KERNEL);
|
||||
if (!pre)
|
||||
return -ENOMEM;
|
||||
pre->dev = &pdev->dev;
|
||||
|
||||
id = of_alias_get_id(np, "pre");
|
||||
if (id < 0) {
|
||||
dev_err(&pdev->dev, "failed to get PRE id\n");
|
||||
return id;
|
||||
}
|
||||
pre->id = id;
|
||||
|
||||
mutex_init(&pre->mutex);
|
||||
spin_lock_init(&pre->lock);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pre->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(pre->base))
|
||||
return PTR_ERR(pre->base);
|
||||
|
||||
pre->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(pre->clk)) {
|
||||
dev_err(&pdev->dev, "failed to get the pre clk\n");
|
||||
return PTR_ERR(pre->clk);
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
err = devm_request_irq(&pdev->dev, irq, ipu_pre_irq_handle,
|
||||
IRQF_TRIGGER_RISING, pdev->name, pre);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to request pre irq\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
pre->iram_pool = of_gen_pool_get(pdev->dev.of_node, "ocram", 0);
|
||||
if (!pre->iram_pool) {
|
||||
dev_err(&pdev->dev, "no iram exist for pre\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mutex_lock(&pre_list_lock);
|
||||
list_add_tail(&pre->list, &pre_list);
|
||||
mutex_unlock(&pre_list_lock);
|
||||
|
||||
ipu_pre_alloc_double_buffer(pre->id, IPU_PRE_MAX_WIDTH * 8 * IPU_PRE_MAX_BPP);
|
||||
|
||||
/* PRE GATE ON */
|
||||
clk_prepare_enable(pre->clk);
|
||||
pre_write(pre, BF_PRE_CTRL_SFTRST(1) | BF_PRE_CTRL_CLKGATE(1),
|
||||
HW_PRE_CTRL_CLR);
|
||||
pre_write(pre, 0xf, HW_PRE_IRQ_MASK);
|
||||
clk_disable_unprepare(pre->clk);
|
||||
|
||||
platform_set_drvdata(pdev, pre);
|
||||
|
||||
dev_info(&pdev->dev, "driver probed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipu_pre_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ipu_pre_data *pre = platform_get_drvdata(pdev);
|
||||
|
||||
if (pre->iram_pool && pre->double_buffer_base) {
|
||||
gen_pool_free(pre->iram_pool,
|
||||
pre->double_buffer_base,
|
||||
pre->double_buffer_size);
|
||||
}
|
||||
|
||||
mutex_lock(&pre_list_lock);
|
||||
list_del(&pre->list);
|
||||
mutex_unlock(&pre_list_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id imx_ipu_pre_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx6q-pre", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx_ipu_pre_dt_ids);
|
||||
|
||||
static struct platform_driver ipu_pre_driver = {
|
||||
.driver = {
|
||||
.name = "imx-pre",
|
||||
.of_match_table = of_match_ptr(imx_ipu_pre_dt_ids),
|
||||
},
|
||||
.probe = ipu_pre_probe,
|
||||
.remove = ipu_pre_remove,
|
||||
};
|
||||
|
||||
static int __init ipu_pre_init(void)
|
||||
{
|
||||
return platform_driver_register(&ipu_pre_driver);
|
||||
}
|
||||
subsys_initcall(ipu_pre_init);
|
||||
|
||||
static void __exit ipu_pre_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ipu_pre_driver);
|
||||
}
|
||||
module_exit(ipu_pre_exit);
|
||||
|
||||
MODULE_DESCRIPTION("i.MX PRE driver");
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Freescale IPU PRG Register Definitions
|
||||
*
|
||||
* Copyright 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#ifndef __IPU_PRG_H__
|
||||
#define __IPU_PRG_H__
|
||||
|
||||
#define IPU_PR_CTRL 0x00
|
||||
#define IPU_PR_STATUS 0x04
|
||||
#define IPU_PR_QOS 0x08
|
||||
#define IPU_PR_REG_UPDATE 0x0c
|
||||
#define IPU_PR_STRIDE(ch) (0x10 + (ch) * 4)
|
||||
#define IPU_PR_CROP_LINE 0x1c
|
||||
#define IPU_PR_ADDR_THD 0x20
|
||||
#define IPU_PR_CH_BADDR(ch) (0x24 + (ch) * 4)
|
||||
#define IPU_PR_CH_OFFSET(ch) (0x30 + (ch) * 4)
|
||||
#define IPU_PR_CH_ILO(ch) (0x3c + (ch) * 4)
|
||||
#define IPU_PR_CH_HEIGHT(ch) (0x48 + (ch) * 4)
|
||||
|
||||
#define IPU_PR_CTRL_CH_BYPASS(ch) (0x1 << (ch))
|
||||
#define IPU_PR_CTRL_SOFT_CH_ARID(ch, n) ((n) << ((ch) * 2 + 8))
|
||||
#define IPU_PR_CTRL_SOFT_CH_ARID_MASK(ch) (0x3 << ((ch) * 2 + 8))
|
||||
#define IPU_PR_CTRL_CH_SO(ch, interlace) ((interlace) << ((ch) + 16))
|
||||
#define IPU_PR_CTRL_CH_SO_MASK(ch) (0x1 << ((ch) + 16))
|
||||
#define IPU_PR_CTRL_CH_VFLIP(ch, vflip) ((vflip) << ((ch) + 19))
|
||||
#define IPU_PR_CTRL_CH_VFLIP_MASK(ch) (0x1 << ((ch) + 19))
|
||||
#define IPU_PR_CTRL_CH_BLOCK_MODE(ch, mode) ((mode) << ((ch) + 22))
|
||||
#define IPU_PR_CTRL_CH_BLOCK_MODE_MASK(ch) (0x1 << ((ch) + 22))
|
||||
#define IPU_PR_CTRL_CH_CNT_LOAD_EN(ch) (0x1 << ((ch) + 25))
|
||||
#define IPU_PR_CTRL_CH_CNT_LOAD_EN_MASK (0x7 << 25)
|
||||
#define IPU_PR_CTRL_SOFTRST BIT(30)
|
||||
#define IPU_PR_CTRL_SHADOW_EN BIT(31)
|
||||
|
||||
#define IPU_PR_STATUS_BUF_RDY(ch, buf) (1 << ((ch) * 2 + (buf)))
|
||||
|
||||
#define IPU_PR_QOS_PRI(id, qos) ((qos) << ((id) * 4))
|
||||
#define IPU_PR_QOS_MASK(id) (0xf << ((id) * 4))
|
||||
|
||||
#define IPU_PR_REG_UPDATE_EN BIT(0)
|
||||
|
||||
#define IPU_PR_STRIDE_MASK 0x3fff
|
||||
|
||||
#define IPU_PR_CROP_LINE_NUM(ch, n) ((n) << ((ch) * 4))
|
||||
#define IPU_PR_CROP_LINE_MASK(ch) (0xf << ((ch) * 4))
|
||||
|
||||
#define IPU_PR_ADDR_THD_MASK 0xffffffff
|
||||
|
||||
#define IPU_PR_CH_BADDR_MASK 0xffffffff
|
||||
|
||||
#define IPU_PR_CH_OFFSET_MASK 0xffffffff
|
||||
|
||||
#define IPU_PR_CH_ILO_MASK 0x007fffff
|
||||
#define IPU_PR_CH_ILO_NUM(ilo) ((ilo) & IPU_PR_CH_ILO_MASK)
|
||||
|
||||
#define IPU_PR_CH_HEIGHT_MASK 0x00000fff
|
||||
#define IPU_PR_CH_HEIGHT_NUM(fh) (((fh) - 1) & IPU_PR_CH_HEIGHT_MASK)
|
||||
#define IPU_PR_CH_IPU_HEIGHT_MASK 0x0fff0000
|
||||
#define IPU_PR_CH_IPU_HEIGHT_NUM(fh) ((((fh) - 1) << 16) & IPU_PR_CH_IPU_HEIGHT_MASK)
|
||||
|
||||
#endif /* __IPU_PRG_H__ */
|
|
@ -0,0 +1,506 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ipu-v3-prg.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include "prg-regs.h"
|
||||
|
||||
#define PRG_CHAN_NUM 3
|
||||
|
||||
struct prg_chan {
|
||||
unsigned int pre_num;
|
||||
struct mutex mutex; /* for in_use */
|
||||
bool in_use;
|
||||
};
|
||||
|
||||
struct ipu_prg_data {
|
||||
unsigned int id;
|
||||
void __iomem *base;
|
||||
unsigned long memory;
|
||||
struct clk *axi_clk;
|
||||
struct clk *apb_clk;
|
||||
struct list_head list;
|
||||
struct device *dev;
|
||||
struct prg_chan chan[PRG_CHAN_NUM];
|
||||
struct regmap *regmap;
|
||||
struct regmap_field *pre_prg_sel[2];
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
static LIST_HEAD(prg_list);
|
||||
static DEFINE_MUTEX(prg_lock);
|
||||
|
||||
static inline void prg_write(struct ipu_prg_data *prg,
|
||||
u32 value, unsigned int offset)
|
||||
{
|
||||
writel(value, prg->base + offset);
|
||||
}
|
||||
|
||||
static inline u32 prg_read(struct ipu_prg_data *prg, unsigned offset)
|
||||
{
|
||||
return readl(prg->base + offset);
|
||||
}
|
||||
|
||||
static struct ipu_prg_data *get_prg(unsigned int ipu_id)
|
||||
{
|
||||
struct ipu_prg_data *prg;
|
||||
|
||||
mutex_lock(&prg_lock);
|
||||
list_for_each_entry(prg, &prg_list, list) {
|
||||
if (prg->id == ipu_id) {
|
||||
mutex_unlock(&prg_lock);
|
||||
return prg;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&prg_lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int assign_prg_chan(struct ipu_prg_data *prg, unsigned int pre_num,
|
||||
ipu_channel_t ipu_ch)
|
||||
{
|
||||
int prg_ch;
|
||||
|
||||
if (!prg)
|
||||
return -EINVAL;
|
||||
|
||||
switch (ipu_ch) {
|
||||
case MEM_BG_SYNC:
|
||||
prg_ch = 0;
|
||||
break;
|
||||
case MEM_FG_SYNC:
|
||||
prg_ch = 1;
|
||||
break;
|
||||
case MEM_DC_SYNC:
|
||||
prg_ch = 2;
|
||||
break;
|
||||
default:
|
||||
dev_err(prg->dev, "wrong ipu channel type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&prg->chan[prg_ch].mutex);
|
||||
if (!prg->chan[prg_ch].in_use) {
|
||||
prg->chan[prg_ch].in_use = true;
|
||||
prg->chan[prg_ch].pre_num = pre_num;
|
||||
|
||||
if (prg_ch != 0) {
|
||||
unsigned int pmux, psel; /* primary */
|
||||
unsigned int smux, ssel; /* secondary */
|
||||
struct regmap_field *pfield, *sfield;
|
||||
|
||||
psel = pre_num - 1;
|
||||
ssel = psel ? 0 : 1;
|
||||
|
||||
pfield = prg->pre_prg_sel[psel];
|
||||
sfield = prg->pre_prg_sel[ssel];
|
||||
pmux = (prg_ch - 1) + (prg->id << 1);
|
||||
|
||||
mutex_lock(&prg_lock);
|
||||
regmap_field_write(pfield, pmux);
|
||||
|
||||
/*
|
||||
* PRE1 and PRE2 cannot bind with a same channel of
|
||||
* one PRG even if one of the two PREs is disabled.
|
||||
*/
|
||||
regmap_field_read(sfield, &smux);
|
||||
if (smux == pmux) {
|
||||
smux = pmux ^ 0x1;
|
||||
regmap_field_write(sfield, smux);
|
||||
}
|
||||
mutex_unlock(&prg_lock);
|
||||
}
|
||||
mutex_unlock(&prg->chan[prg_ch].mutex);
|
||||
dev_dbg(prg->dev, "bind prg%u ch%d with pre%u\n",
|
||||
prg->id, prg_ch, pre_num);
|
||||
return prg_ch;
|
||||
}
|
||||
mutex_unlock(&prg->chan[prg_ch].mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static inline int get_prg_chan(struct ipu_prg_data *prg, unsigned int pre_num)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!prg)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < PRG_CHAN_NUM; i++) {
|
||||
mutex_lock(&prg->chan[i].mutex);
|
||||
if (prg->chan[i].in_use &&
|
||||
prg->chan[i].pre_num == pre_num) {
|
||||
mutex_unlock(&prg->chan[i].mutex);
|
||||
return i;
|
||||
}
|
||||
mutex_unlock(&prg->chan[i].mutex);
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int ipu_prg_config(struct ipu_prg_config *config)
|
||||
{
|
||||
struct ipu_prg_data *prg = get_prg(config->id);
|
||||
struct ipu_soc *ipu = ipu_get_soc(config->id);
|
||||
int prg_ch, axi_id;
|
||||
u32 reg;
|
||||
|
||||
if (!prg || config->crop_line > 3 || !ipu)
|
||||
return -EINVAL;
|
||||
|
||||
if (config->height & ~IPU_PR_CH_HEIGHT_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
prg_ch = assign_prg_chan(prg, config->pre_num, config->ipu_ch);
|
||||
if (prg_ch < 0)
|
||||
return prg_ch;
|
||||
|
||||
axi_id = ipu_ch_param_get_axi_id(ipu, config->ipu_ch, IPU_INPUT_BUFFER);
|
||||
|
||||
clk_prepare_enable(prg->axi_clk);
|
||||
clk_prepare_enable(prg->apb_clk);
|
||||
|
||||
spin_lock(&prg->lock);
|
||||
/* clear all load enable to impact other channels */
|
||||
reg = prg_read(prg, IPU_PR_CTRL);
|
||||
reg &= ~IPU_PR_CTRL_CH_CNT_LOAD_EN_MASK;
|
||||
prg_write(prg, reg, IPU_PR_CTRL);
|
||||
|
||||
/* counter load enable */
|
||||
reg = prg_read(prg, IPU_PR_CTRL);
|
||||
reg |= IPU_PR_CTRL_CH_CNT_LOAD_EN(prg_ch);
|
||||
prg_write(prg, reg, IPU_PR_CTRL);
|
||||
|
||||
/* AXI ID */
|
||||
reg = prg_read(prg, IPU_PR_CTRL);
|
||||
reg &= ~IPU_PR_CTRL_SOFT_CH_ARID_MASK(prg_ch);
|
||||
reg |= IPU_PR_CTRL_SOFT_CH_ARID(prg_ch, axi_id);
|
||||
prg_write(prg, reg, IPU_PR_CTRL);
|
||||
|
||||
/* so */
|
||||
reg = prg_read(prg, IPU_PR_CTRL);
|
||||
reg &= ~IPU_PR_CTRL_CH_SO_MASK(prg_ch);
|
||||
reg |= IPU_PR_CTRL_CH_SO(prg_ch, config->so);
|
||||
prg_write(prg, reg, IPU_PR_CTRL);
|
||||
|
||||
/* vflip */
|
||||
reg = prg_read(prg, IPU_PR_CTRL);
|
||||
reg &= ~IPU_PR_CTRL_CH_VFLIP_MASK(prg_ch);
|
||||
reg |= IPU_PR_CTRL_CH_VFLIP(prg_ch, config->vflip);
|
||||
prg_write(prg, reg, IPU_PR_CTRL);
|
||||
|
||||
/* block mode */
|
||||
reg = prg_read(prg, IPU_PR_CTRL);
|
||||
reg &= ~IPU_PR_CTRL_CH_BLOCK_MODE_MASK(prg_ch);
|
||||
reg |= IPU_PR_CTRL_CH_BLOCK_MODE(prg_ch, config->block_mode);
|
||||
prg_write(prg, reg, IPU_PR_CTRL);
|
||||
|
||||
/* disable bypass */
|
||||
reg = prg_read(prg, IPU_PR_CTRL);
|
||||
reg &= ~IPU_PR_CTRL_CH_BYPASS(prg_ch);
|
||||
prg_write(prg, reg, IPU_PR_CTRL);
|
||||
|
||||
/* stride */
|
||||
reg = prg_read(prg, IPU_PR_STRIDE(prg_ch));
|
||||
reg &= ~IPU_PR_STRIDE_MASK;
|
||||
reg |= config->stride - 1;
|
||||
prg_write(prg, reg, IPU_PR_STRIDE(prg_ch));
|
||||
|
||||
/* ilo */
|
||||
reg = prg_read(prg, IPU_PR_CH_ILO(prg_ch));
|
||||
reg &= ~IPU_PR_CH_ILO_MASK;
|
||||
reg |= IPU_PR_CH_ILO_NUM(config->ilo);
|
||||
prg_write(prg, reg, IPU_PR_CH_ILO(prg_ch));
|
||||
|
||||
/* height */
|
||||
reg = prg_read(prg, IPU_PR_CH_HEIGHT(prg_ch));
|
||||
reg &= ~IPU_PR_CH_HEIGHT_MASK;
|
||||
reg |= IPU_PR_CH_HEIGHT_NUM(config->height);
|
||||
prg_write(prg, reg, IPU_PR_CH_HEIGHT(prg_ch));
|
||||
|
||||
/* ipu height */
|
||||
reg = prg_read(prg, IPU_PR_CH_HEIGHT(prg_ch));
|
||||
reg &= ~IPU_PR_CH_IPU_HEIGHT_MASK;
|
||||
reg |= IPU_PR_CH_IPU_HEIGHT_NUM(config->ipu_height);
|
||||
prg_write(prg, reg, IPU_PR_CH_HEIGHT(prg_ch));
|
||||
|
||||
/* crop */
|
||||
reg = prg_read(prg, IPU_PR_CROP_LINE);
|
||||
reg &= ~IPU_PR_CROP_LINE_MASK(prg_ch);
|
||||
reg |= IPU_PR_CROP_LINE_NUM(prg_ch, config->crop_line);
|
||||
prg_write(prg, reg, IPU_PR_CROP_LINE);
|
||||
|
||||
/* buffer address */
|
||||
reg = prg_read(prg, IPU_PR_CH_BADDR(prg_ch));
|
||||
reg &= ~IPU_PR_CH_BADDR_MASK;
|
||||
reg |= config->baddr;
|
||||
prg_write(prg, reg, IPU_PR_CH_BADDR(prg_ch));
|
||||
|
||||
/* offset */
|
||||
reg = prg_read(prg, IPU_PR_CH_OFFSET(prg_ch));
|
||||
reg &= ~IPU_PR_CH_OFFSET_MASK;
|
||||
reg |= config->offset;
|
||||
prg_write(prg, reg, IPU_PR_CH_OFFSET(prg_ch));
|
||||
|
||||
/* threshold */
|
||||
reg = prg_read(prg, IPU_PR_ADDR_THD);
|
||||
reg &= ~IPU_PR_ADDR_THD_MASK;
|
||||
reg |= prg->memory;
|
||||
prg_write(prg, reg, IPU_PR_ADDR_THD);
|
||||
|
||||
/* shadow enable */
|
||||
reg = prg_read(prg, IPU_PR_CTRL);
|
||||
reg |= IPU_PR_CTRL_SHADOW_EN;
|
||||
prg_write(prg, reg, IPU_PR_CTRL);
|
||||
|
||||
/* register update */
|
||||
reg = prg_read(prg, IPU_PR_REG_UPDATE);
|
||||
reg |= IPU_PR_REG_UPDATE_EN;
|
||||
prg_write(prg, reg, IPU_PR_REG_UPDATE);
|
||||
spin_unlock(&prg->lock);
|
||||
|
||||
clk_disable_unprepare(prg->apb_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_prg_config);
|
||||
|
||||
int ipu_prg_disable(unsigned int ipu_id, unsigned int pre_num)
|
||||
{
|
||||
struct ipu_prg_data *prg = get_prg(ipu_id);
|
||||
int prg_ch;
|
||||
u32 reg;
|
||||
|
||||
if (!prg)
|
||||
return -EINVAL;
|
||||
|
||||
prg_ch = get_prg_chan(prg, pre_num);
|
||||
if (prg_ch < 0)
|
||||
return prg_ch;
|
||||
|
||||
clk_prepare_enable(prg->apb_clk);
|
||||
|
||||
spin_lock(&prg->lock);
|
||||
/* clear all load enable to impact other channels */
|
||||
reg = prg_read(prg, IPU_PR_CTRL);
|
||||
reg &= ~IPU_PR_CTRL_CH_CNT_LOAD_EN_MASK;
|
||||
prg_write(prg, reg, IPU_PR_CTRL);
|
||||
|
||||
/* counter load enable */
|
||||
reg = prg_read(prg, IPU_PR_CTRL);
|
||||
reg |= IPU_PR_CTRL_CH_CNT_LOAD_EN(prg_ch);
|
||||
prg_write(prg, reg, IPU_PR_CTRL);
|
||||
|
||||
/* enable bypass */
|
||||
reg = prg_read(prg, IPU_PR_CTRL);
|
||||
reg |= IPU_PR_CTRL_CH_BYPASS(prg_ch);
|
||||
prg_write(prg, reg, IPU_PR_CTRL);
|
||||
|
||||
/* shadow enable */
|
||||
reg = prg_read(prg, IPU_PR_CTRL);
|
||||
reg |= IPU_PR_CTRL_SHADOW_EN;
|
||||
prg_write(prg, reg, IPU_PR_CTRL);
|
||||
|
||||
/* register update */
|
||||
reg = prg_read(prg, IPU_PR_REG_UPDATE);
|
||||
reg |= IPU_PR_REG_UPDATE_EN;
|
||||
prg_write(prg, reg, IPU_PR_REG_UPDATE);
|
||||
spin_unlock(&prg->lock);
|
||||
|
||||
clk_disable_unprepare(prg->apb_clk);
|
||||
clk_disable_unprepare(prg->axi_clk);
|
||||
|
||||
mutex_lock(&prg->chan[prg_ch].mutex);
|
||||
prg->chan[prg_ch].in_use = false;
|
||||
mutex_unlock(&prg->chan[prg_ch].mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_prg_disable);
|
||||
|
||||
int ipu_prg_wait_buf_ready(unsigned int ipu_id, unsigned int pre_num,
|
||||
unsigned int hsk_line_num,
|
||||
int pre_store_out_height)
|
||||
{
|
||||
struct ipu_prg_data *prg = get_prg(ipu_id);
|
||||
int prg_ch, timeout = 1000;
|
||||
u32 reg;
|
||||
|
||||
if (!prg)
|
||||
return -EINVAL;
|
||||
|
||||
prg_ch = get_prg_chan(prg, pre_num);
|
||||
if (prg_ch < 0)
|
||||
return prg_ch;
|
||||
|
||||
clk_prepare_enable(prg->apb_clk);
|
||||
|
||||
spin_lock(&prg->lock);
|
||||
if (pre_store_out_height <= (4 << hsk_line_num)) {
|
||||
do {
|
||||
reg = prg_read(prg, IPU_PR_STATUS);
|
||||
udelay(1000);
|
||||
timeout--;
|
||||
} while (!(reg & IPU_PR_STATUS_BUF_RDY(prg_ch, 0)) && timeout);
|
||||
} else {
|
||||
do {
|
||||
reg = prg_read(prg, IPU_PR_STATUS);
|
||||
udelay(1000);
|
||||
timeout--;
|
||||
} while ((!(reg & IPU_PR_STATUS_BUF_RDY(prg_ch, 0)) ||
|
||||
!(reg & IPU_PR_STATUS_BUF_RDY(prg_ch, 1))) && timeout);
|
||||
}
|
||||
spin_unlock(&prg->lock);
|
||||
|
||||
clk_disable_unprepare(prg->apb_clk);
|
||||
|
||||
if (!timeout)
|
||||
dev_err(prg->dev, "wait for buffer ready timeout\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ipu_prg_wait_buf_ready);
|
||||
|
||||
static int ipu_prg_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node, *memory;
|
||||
struct ipu_prg_data *prg;
|
||||
struct resource *res;
|
||||
struct reg_field reg_field0 = REG_FIELD(IOMUXC_GPR5,
|
||||
IMX6Q_GPR5_PRE_PRG_SEL0_LSB,
|
||||
IMX6Q_GPR5_PRE_PRG_SEL0_MSB);
|
||||
struct reg_field reg_field1 = REG_FIELD(IOMUXC_GPR5,
|
||||
IMX6Q_GPR5_PRE_PRG_SEL1_LSB,
|
||||
IMX6Q_GPR5_PRE_PRG_SEL1_MSB);
|
||||
int id, i;
|
||||
|
||||
prg = devm_kzalloc(&pdev->dev, sizeof(*prg), GFP_KERNEL);
|
||||
if (!prg)
|
||||
return -ENOMEM;
|
||||
prg->dev = &pdev->dev;
|
||||
|
||||
for (i = 0; i < PRG_CHAN_NUM; i++)
|
||||
mutex_init(&prg->chan[i].mutex);
|
||||
|
||||
spin_lock_init(&prg->lock);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
prg->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(prg->base))
|
||||
return PTR_ERR(prg->base);
|
||||
|
||||
prg->axi_clk = devm_clk_get(&pdev->dev, "axi");
|
||||
if (IS_ERR(prg->axi_clk)) {
|
||||
dev_err(&pdev->dev, "failed to get the axi clk\n");
|
||||
return PTR_ERR(prg->axi_clk);
|
||||
}
|
||||
|
||||
prg->apb_clk = devm_clk_get(&pdev->dev, "apb");
|
||||
if (IS_ERR(prg->apb_clk)) {
|
||||
dev_err(&pdev->dev, "failed to get the apb clk\n");
|
||||
return PTR_ERR(prg->apb_clk);
|
||||
}
|
||||
|
||||
prg->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
|
||||
if (IS_ERR(prg->regmap)) {
|
||||
dev_err(&pdev->dev, "failed to get regmap\n");
|
||||
return PTR_ERR(prg->regmap);
|
||||
}
|
||||
|
||||
prg->pre_prg_sel[0] = devm_regmap_field_alloc(&pdev->dev, prg->regmap,
|
||||
reg_field0);
|
||||
if (IS_ERR(prg->pre_prg_sel[0]))
|
||||
return PTR_ERR(prg->pre_prg_sel[0]);
|
||||
|
||||
prg->pre_prg_sel[1] = devm_regmap_field_alloc(&pdev->dev, prg->regmap,
|
||||
reg_field1);
|
||||
if (IS_ERR(prg->pre_prg_sel[1]))
|
||||
return PTR_ERR(prg->pre_prg_sel[1]);
|
||||
|
||||
memory = of_parse_phandle(np, "memory-region", 0);
|
||||
if (!memory)
|
||||
return -ENODEV;
|
||||
|
||||
prg->memory = of_translate_address(memory,
|
||||
of_get_address(memory, 0, NULL, NULL));
|
||||
|
||||
id = of_alias_get_id(np, "prg");
|
||||
if (id < 0) {
|
||||
dev_err(&pdev->dev, "failed to get PRG id\n");
|
||||
return id;
|
||||
}
|
||||
prg->id = id;
|
||||
|
||||
mutex_lock(&prg_lock);
|
||||
list_add_tail(&prg->list, &prg_list);
|
||||
mutex_unlock(&prg_lock);
|
||||
|
||||
platform_set_drvdata(pdev, prg);
|
||||
|
||||
dev_info(&pdev->dev, "driver probed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipu_prg_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ipu_prg_data *prg = platform_get_drvdata(pdev);
|
||||
|
||||
mutex_lock(&prg_lock);
|
||||
list_del(&prg->list);
|
||||
mutex_unlock(&prg_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id imx_ipu_prg_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx6q-prg", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx_ipu_prg_dt_ids);
|
||||
|
||||
static struct platform_driver ipu_prg_driver = {
|
||||
.driver = {
|
||||
.name = "imx-prg",
|
||||
.of_match_table = of_match_ptr(imx_ipu_prg_dt_ids),
|
||||
},
|
||||
.probe = ipu_prg_probe,
|
||||
.remove = ipu_prg_remove,
|
||||
};
|
||||
|
||||
static int __init ipu_prg_init(void)
|
||||
{
|
||||
return platform_driver_register(&ipu_prg_driver);
|
||||
}
|
||||
subsys_initcall(ipu_prg_init);
|
||||
|
||||
static void __exit ipu_prg_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ipu_prg_driver);
|
||||
}
|
||||
module_exit(ipu_prg_exit);
|
||||
|
||||
MODULE_DESCRIPTION("i.MX PRG driver");
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,536 @@
|
|||
/*
|
||||
* Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ipu.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "vdoa.h"
|
||||
/* 6band(3field* double buffer) * (width*2) * bandline(8)
|
||||
= 6x1024x2x8 = 96k or 72k(1.5byte) */
|
||||
#define MAX_VDOA_IRAM_SIZE (1024*96)
|
||||
#define VDOA_IRAM_SIZE (1024*72)
|
||||
|
||||
#define VDOAC_BAND_HEIGHT_32LINES (32)
|
||||
#define VDOAC_BAND_HEIGHT_16LINES (16)
|
||||
#define VDOAC_BAND_HEIGHT_8LINES (8)
|
||||
#define VDOAC_THREE_FRAMES (0x1 << 2)
|
||||
#define VDOAC_SYNC_BAND_MODE (0x1 << 3)
|
||||
#define VDOAC_SCAN_ORDER_INTERLACED (0x1 << 4)
|
||||
#define VDOAC_PFS_YUYV (0x1 << 5)
|
||||
#define VDOAC_IPU_SEL_1 (0x1 << 6)
|
||||
#define VDOAFP_FH_MASK (0x1FFF)
|
||||
#define VDOAFP_FH_SHIFT (16)
|
||||
#define VDOAFP_FW_MASK (0x3FFF)
|
||||
#define VDOAFP_FW_SHIFT (0)
|
||||
#define VDOASL_VSLY_MASK (0x3FFF)
|
||||
#define VDOASL_VSLY_SHIFT (16)
|
||||
#define VDOASL_ISLY_MASK (0x7FFF)
|
||||
#define VDOASL_ISLY_SHIFT (0)
|
||||
#define VDOASRR_START_XFER (0x2)
|
||||
#define VDOASRR_SWRST (0x1)
|
||||
#define VDOAIEIST_TRANSFER_ERR (0x2)
|
||||
#define VDOAIEIST_TRANSFER_END (0x1)
|
||||
|
||||
#define VDOAC (0x0) /* Control Register */
|
||||
#define VDOASRR (0x4) /* Start and Reset Register */
|
||||
#define VDOAIE (0x8) /* Interrupt Enable Register */
|
||||
#define VDOAIST (0xc) /* Interrupt Status Register */
|
||||
#define VDOAFP (0x10) /* Frame Parameters Register */
|
||||
#define VDOAIEBA00 (0x14) /* External Buffer n Frame m Address Register */
|
||||
#define VDOAIEBA01 (0x18) /* External Buffer n Frame m Address Register */
|
||||
#define VDOAIEBA02 (0x1c) /* External Buffer n Frame m Address Register */
|
||||
#define VDOAIEBA10 (0x20) /* External Buffer n Frame m Address Register */
|
||||
#define VDOAIEBA11 (0x24) /* External Buffer n Frame m Address Register */
|
||||
#define VDOAIEBA12 (0x28) /* External Buffer n Frame m Address Register */
|
||||
#define VDOASL (0x2c) /* IPU Stride Line Register */
|
||||
#define VDOAIUBO (0x30) /* IPU Chroma Buffer Offset Register */
|
||||
#define VDOAVEBA0 (0x34) /* External Buffer m Address Register */
|
||||
#define VDOAVEBA1 (0x38) /* External Buffer m Address Register */
|
||||
#define VDOAVEBA2 (0x3c) /* External Buffer m Address Register */
|
||||
#define VDOAVUBO (0x40) /* VPU Chroma Buffer Offset */
|
||||
#define VDOASR (0x44) /* Status Register */
|
||||
#define VDOATD (0x48) /* Test Debug Register */
|
||||
|
||||
|
||||
enum {
|
||||
VDOA_INIT = 0x1,
|
||||
VDOA_GET = 0x2,
|
||||
VDOA_SETUP = 0x4,
|
||||
VDOA_GET_OBUF = 0x8,
|
||||
VDOA_START = 0x10,
|
||||
VDOA_INIRQ = 0x20,
|
||||
VDOA_STOP = 0x40,
|
||||
VDOA_PUT = VDOA_INIT,
|
||||
};
|
||||
|
||||
enum {
|
||||
VDOA_NULL = 0,
|
||||
VDOA_FRAME = 1,
|
||||
VDOA_PREV_FIELD = 2,
|
||||
VDOA_CURR_FIELD = 3,
|
||||
VDOA_NEXT_FIELD = 4,
|
||||
};
|
||||
|
||||
#define CHECK_STATE(expect, retcode) \
|
||||
do { \
|
||||
if (!((expect) & vdoa->state)) { \
|
||||
dev_err(vdoa->dev, "ERR: %s state:0x%x, expect:0x%x.\n",\
|
||||
__func__, vdoa->state, (expect)); \
|
||||
retcode; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_NULL_PTR(ptr) \
|
||||
do { \
|
||||
pr_debug("vdoa_ptr:0x%p in %s state:0x%x.\n", \
|
||||
vdoa, __func__, vdoa->state); \
|
||||
if (NULL == (ptr)) { \
|
||||
pr_err("ERR vdoa: %s state:0x%x null ptr.\n", \
|
||||
__func__, vdoa->state); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
struct vdoa_info {
|
||||
int state;
|
||||
struct device *dev;
|
||||
struct clk *vdoa_clk;
|
||||
void __iomem *reg_base;
|
||||
struct gen_pool *iram_pool;
|
||||
unsigned long iram_base;
|
||||
unsigned long iram_paddr;
|
||||
int irq;
|
||||
int field;
|
||||
struct completion comp;
|
||||
};
|
||||
|
||||
static struct vdoa_info *g_vdoa;
|
||||
static unsigned long iram_size;
|
||||
static DEFINE_MUTEX(vdoa_lock);
|
||||
|
||||
static inline void vdoa_read_register(struct vdoa_info *vdoa,
|
||||
u32 reg, u32 *val)
|
||||
{
|
||||
*val = ioread32(vdoa->reg_base + reg);
|
||||
dev_dbg(vdoa->dev, "read_reg:0x%02x, val:0x%08x.\n", reg, *val);
|
||||
}
|
||||
|
||||
static inline void vdoa_write_register(struct vdoa_info *vdoa,
|
||||
u32 reg, u32 val)
|
||||
{
|
||||
iowrite32(val, vdoa->reg_base + reg);
|
||||
dev_dbg(vdoa->dev, "\t\twrite_reg:0x%02x, val:0x%08x.\n", reg, val);
|
||||
}
|
||||
|
||||
static void dump_registers(struct vdoa_info *vdoa)
|
||||
{
|
||||
int i;
|
||||
u32 data;
|
||||
|
||||
for (i = VDOAC; i < VDOATD; i += 4)
|
||||
vdoa_read_register(vdoa, i, &data);
|
||||
}
|
||||
|
||||
int vdoa_setup(vdoa_handle_t handle, struct vdoa_params *params)
|
||||
{
|
||||
int band_size;
|
||||
int total_band_size = 0;
|
||||
int ipu_stride;
|
||||
u32 data;
|
||||
struct vdoa_info *vdoa = (struct vdoa_info *)handle;
|
||||
|
||||
CHECK_NULL_PTR(vdoa);
|
||||
CHECK_STATE(VDOA_GET | VDOA_GET_OBUF | VDOA_STOP, return -EINVAL);
|
||||
if (VDOA_GET == vdoa->state) {
|
||||
dev_dbg(vdoa->dev, "w:%d, h:%d.\n",
|
||||
params->width, params->height);
|
||||
data = (params->band_lines == VDOAC_BAND_HEIGHT_32LINES) ? 2 :
|
||||
((params->band_lines == VDOAC_BAND_HEIGHT_16LINES) ?
|
||||
1 : 0);
|
||||
data |= params->scan_order ? VDOAC_SCAN_ORDER_INTERLACED : 0;
|
||||
data |= params->band_mode ? VDOAC_SYNC_BAND_MODE : 0;
|
||||
data |= params->pfs ? VDOAC_PFS_YUYV : 0;
|
||||
data |= params->ipu_num ? VDOAC_IPU_SEL_1 : 0;
|
||||
vdoa_write_register(vdoa, VDOAC, data);
|
||||
|
||||
data = ((params->width & VDOAFP_FW_MASK) << VDOAFP_FW_SHIFT) |
|
||||
((params->height & VDOAFP_FH_MASK) << VDOAFP_FH_SHIFT);
|
||||
vdoa_write_register(vdoa, VDOAFP, data);
|
||||
|
||||
ipu_stride = params->pfs ? params->width << 1 : params->width;
|
||||
data = ((params->vpu_stride & VDOASL_VSLY_MASK) <<
|
||||
VDOASL_VSLY_SHIFT) |
|
||||
((ipu_stride & VDOASL_ISLY_MASK) << VDOASL_ISLY_SHIFT);
|
||||
vdoa_write_register(vdoa, VDOASL, data);
|
||||
|
||||
dev_dbg(vdoa->dev, "band_mode:%d, band_line:%d, base:0x%lx.\n",
|
||||
params->band_mode, params->band_lines, vdoa->iram_paddr);
|
||||
}
|
||||
/*
|
||||
* band size = (luma_per_line + chroma_per_line) * bandLines
|
||||
* = width * (3/2 or 2) * bandLines
|
||||
* double buffer mode used.
|
||||
*/
|
||||
if (params->pfs)
|
||||
band_size = (params->width << 1) * params->band_lines;
|
||||
else
|
||||
band_size = ((params->width * 3) >> 1) *
|
||||
params->band_lines;
|
||||
if (params->interlaced) {
|
||||
total_band_size = 6 * band_size; /* 3 frames*double buffer */
|
||||
if (iram_size < total_band_size) {
|
||||
dev_err(vdoa->dev, "iram_size:0x%lx is smaller than "
|
||||
"request:0x%x!\n", iram_size, total_band_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (params->vfield_buf.prev_veba) {
|
||||
if (params->band_mode) {
|
||||
vdoa_write_register(vdoa, VDOAIEBA00,
|
||||
vdoa->iram_paddr);
|
||||
vdoa_write_register(vdoa, VDOAIEBA10,
|
||||
vdoa->iram_paddr + band_size);
|
||||
} else
|
||||
vdoa_write_register(vdoa, VDOAIEBA00,
|
||||
params->ieba0);
|
||||
vdoa_write_register(vdoa, VDOAVEBA0,
|
||||
params->vfield_buf.prev_veba);
|
||||
vdoa->field = VDOA_PREV_FIELD;
|
||||
}
|
||||
if (params->vfield_buf.cur_veba) {
|
||||
if (params->band_mode) {
|
||||
vdoa_write_register(vdoa, VDOAIEBA01,
|
||||
vdoa->iram_paddr + band_size * 2);
|
||||
vdoa_write_register(vdoa, VDOAIEBA11,
|
||||
vdoa->iram_paddr + band_size * 3);
|
||||
} else
|
||||
vdoa_write_register(vdoa, VDOAIEBA01,
|
||||
params->ieba1);
|
||||
vdoa_write_register(vdoa, VDOAVEBA1,
|
||||
params->vfield_buf.cur_veba);
|
||||
vdoa->field = VDOA_CURR_FIELD;
|
||||
}
|
||||
if (params->vfield_buf.next_veba) {
|
||||
if (params->band_mode) {
|
||||
vdoa_write_register(vdoa, VDOAIEBA02,
|
||||
vdoa->iram_paddr + band_size * 4);
|
||||
vdoa_write_register(vdoa, VDOAIEBA12,
|
||||
vdoa->iram_paddr + band_size * 5);
|
||||
} else
|
||||
vdoa_write_register(vdoa, VDOAIEBA02,
|
||||
params->ieba2);
|
||||
vdoa_write_register(vdoa, VDOAVEBA2,
|
||||
params->vfield_buf.next_veba);
|
||||
vdoa->field = VDOA_NEXT_FIELD;
|
||||
vdoa_read_register(vdoa, VDOAC, &data);
|
||||
data |= VDOAC_THREE_FRAMES;
|
||||
vdoa_write_register(vdoa, VDOAC, data);
|
||||
}
|
||||
|
||||
if (!params->pfs)
|
||||
vdoa_write_register(vdoa, VDOAIUBO,
|
||||
params->width * params->band_lines);
|
||||
vdoa_write_register(vdoa, VDOAVUBO,
|
||||
params->vfield_buf.vubo);
|
||||
dev_dbg(vdoa->dev, "total band_size:0x%x.\n", band_size*6);
|
||||
} else if (params->band_mode) {
|
||||
/* used for progressive frame resize on PrP channel */
|
||||
BUG(); /* currently not support */
|
||||
/* progressvie frame: band mode */
|
||||
vdoa_write_register(vdoa, VDOAIEBA00, vdoa->iram_paddr);
|
||||
vdoa_write_register(vdoa, VDOAIEBA10,
|
||||
vdoa->iram_paddr + band_size);
|
||||
if (!params->pfs)
|
||||
vdoa_write_register(vdoa, VDOAIUBO,
|
||||
params->width * params->band_lines);
|
||||
dev_dbg(vdoa->dev, "total band_size:0x%x\n", band_size*2);
|
||||
} else {
|
||||
/* progressive frame: mem->mem, non-band mode */
|
||||
vdoa->field = VDOA_FRAME;
|
||||
vdoa_write_register(vdoa, VDOAVEBA0, params->vframe_buf.veba);
|
||||
vdoa_write_register(vdoa, VDOAVUBO, params->vframe_buf.vubo);
|
||||
vdoa_write_register(vdoa, VDOAIEBA00, params->ieba0);
|
||||
if (!params->pfs)
|
||||
/* note: iubo is relative value, based on ieba0 */
|
||||
vdoa_write_register(vdoa, VDOAIUBO,
|
||||
params->width * params->height);
|
||||
}
|
||||
vdoa->state = VDOA_SETUP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vdoa_get_output_buf(vdoa_handle_t handle, struct vdoa_ipu_buf *buf)
|
||||
{
|
||||
u32 data;
|
||||
struct vdoa_info *vdoa = (struct vdoa_info *)handle;
|
||||
|
||||
CHECK_NULL_PTR(vdoa);
|
||||
CHECK_STATE(VDOA_SETUP, return);
|
||||
vdoa->state = VDOA_GET_OBUF;
|
||||
memset(buf, 0, sizeof(*buf));
|
||||
|
||||
vdoa_read_register(vdoa, VDOAC, &data);
|
||||
switch (vdoa->field) {
|
||||
case VDOA_FRAME:
|
||||
case VDOA_PREV_FIELD:
|
||||
vdoa_read_register(vdoa, VDOAIEBA00, &buf->ieba0);
|
||||
if (data & VDOAC_SYNC_BAND_MODE)
|
||||
vdoa_read_register(vdoa, VDOAIEBA10, &buf->ieba1);
|
||||
break;
|
||||
case VDOA_CURR_FIELD:
|
||||
vdoa_read_register(vdoa, VDOAIEBA01, &buf->ieba0);
|
||||
vdoa_read_register(vdoa, VDOAIEBA11, &buf->ieba1);
|
||||
break;
|
||||
case VDOA_NEXT_FIELD:
|
||||
vdoa_read_register(vdoa, VDOAIEBA02, &buf->ieba0);
|
||||
vdoa_read_register(vdoa, VDOAIEBA12, &buf->ieba1);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
if (!(data & VDOAC_PFS_YUYV))
|
||||
vdoa_read_register(vdoa, VDOAIUBO, &buf->iubo);
|
||||
}
|
||||
|
||||
int vdoa_start(vdoa_handle_t handle, int timeout_ms)
|
||||
{
|
||||
int ret;
|
||||
struct vdoa_info *vdoa = (struct vdoa_info *)handle;
|
||||
|
||||
CHECK_NULL_PTR(vdoa);
|
||||
CHECK_STATE(VDOA_GET_OBUF, return -EINVAL);
|
||||
vdoa->state = VDOA_START;
|
||||
init_completion(&vdoa->comp);
|
||||
vdoa_write_register(vdoa, VDOAIST,
|
||||
VDOAIEIST_TRANSFER_ERR | VDOAIEIST_TRANSFER_END);
|
||||
vdoa_write_register(vdoa, VDOAIE,
|
||||
VDOAIEIST_TRANSFER_ERR | VDOAIEIST_TRANSFER_END);
|
||||
|
||||
enable_irq(vdoa->irq);
|
||||
vdoa_write_register(vdoa, VDOASRR, VDOASRR_START_XFER);
|
||||
dump_registers(vdoa);
|
||||
|
||||
ret = wait_for_completion_timeout(&vdoa->comp,
|
||||
msecs_to_jiffies(timeout_ms));
|
||||
|
||||
return ret > 0 ? 0 : -ETIMEDOUT;
|
||||
}
|
||||
|
||||
void vdoa_stop(vdoa_handle_t handle)
|
||||
{
|
||||
struct vdoa_info *vdoa = (struct vdoa_info *)handle;
|
||||
|
||||
CHECK_NULL_PTR(vdoa);
|
||||
CHECK_STATE(VDOA_GET | VDOA_START | VDOA_INIRQ, return);
|
||||
vdoa->state = VDOA_STOP;
|
||||
|
||||
disable_irq(vdoa->irq);
|
||||
|
||||
vdoa_write_register(vdoa, VDOASRR, VDOASRR_SWRST);
|
||||
}
|
||||
|
||||
void vdoa_get_handle(vdoa_handle_t *handle)
|
||||
{
|
||||
struct vdoa_info *vdoa = g_vdoa;
|
||||
|
||||
CHECK_NULL_PTR(handle);
|
||||
*handle = (vdoa_handle_t *)NULL;
|
||||
CHECK_STATE(VDOA_INIT, return);
|
||||
mutex_lock(&vdoa_lock);
|
||||
clk_prepare_enable(vdoa->vdoa_clk);
|
||||
vdoa->state = VDOA_GET;
|
||||
vdoa->field = VDOA_NULL;
|
||||
vdoa_write_register(vdoa, VDOASRR, VDOASRR_SWRST);
|
||||
|
||||
*handle = (vdoa_handle_t *)vdoa;
|
||||
}
|
||||
|
||||
void vdoa_put_handle(vdoa_handle_t *handle)
|
||||
{
|
||||
struct vdoa_info *vdoa = (struct vdoa_info *)(*handle);
|
||||
|
||||
CHECK_NULL_PTR(vdoa);
|
||||
CHECK_STATE(VDOA_STOP, return);
|
||||
if (vdoa != g_vdoa)
|
||||
BUG();
|
||||
|
||||
clk_disable_unprepare(vdoa->vdoa_clk);
|
||||
vdoa->state = VDOA_PUT;
|
||||
*handle = (vdoa_handle_t *)NULL;
|
||||
mutex_unlock(&vdoa_lock);
|
||||
}
|
||||
|
||||
static irqreturn_t vdoa_irq_handler(int irq, void *data)
|
||||
{
|
||||
u32 status, mask, val;
|
||||
struct vdoa_info *vdoa = data;
|
||||
|
||||
CHECK_NULL_PTR(vdoa);
|
||||
CHECK_STATE(VDOA_START, return IRQ_HANDLED);
|
||||
vdoa->state = VDOA_INIRQ;
|
||||
vdoa_read_register(vdoa, VDOAIST, &status);
|
||||
vdoa_read_register(vdoa, VDOAIE, &mask);
|
||||
val = status & mask;
|
||||
vdoa_write_register(vdoa, VDOAIST, val);
|
||||
if (VDOAIEIST_TRANSFER_ERR & val)
|
||||
dev_err(vdoa->dev, "vdoa Transfer err irq!\n");
|
||||
if (VDOAIEIST_TRANSFER_END & val)
|
||||
dev_dbg(vdoa->dev, "vdoa Transfer end irq!\n");
|
||||
if (0 == val) {
|
||||
dev_err(vdoa->dev, "vdoa unknown irq!\n");
|
||||
BUG();
|
||||
}
|
||||
|
||||
complete(&vdoa->comp);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* IRAM Size in Kbytes, example:vdoa_iram_size=64, 64KBytes */
|
||||
static int __init vdoa_iram_size_setup(char *options)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = kstrtoul(options, 0, &iram_size);
|
||||
if (ret)
|
||||
iram_size = 0;
|
||||
else
|
||||
iram_size *= SZ_1K;
|
||||
|
||||
return 1;
|
||||
}
|
||||
__setup("vdoa_iram_size=", vdoa_iram_size_setup);
|
||||
|
||||
static const struct of_device_id imx_vdoa_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx6q-vdoa", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static int vdoa_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct vdoa_info *vdoa;
|
||||
struct resource *res;
|
||||
struct resource *res_irq;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "can't get device resources\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res_irq) {
|
||||
dev_err(dev, "failed to get irq resource\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
vdoa = devm_kzalloc(dev, sizeof(struct vdoa_info), GFP_KERNEL);
|
||||
if (!vdoa)
|
||||
return -ENOMEM;
|
||||
vdoa->dev = dev;
|
||||
|
||||
vdoa->reg_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (!vdoa->reg_base)
|
||||
return -EBUSY;
|
||||
|
||||
vdoa->irq = res_irq->start;
|
||||
ret = devm_request_irq(dev, vdoa->irq, vdoa_irq_handler, 0,
|
||||
"vdoa", vdoa);
|
||||
if (ret) {
|
||||
dev_err(dev, "can't claim irq %d\n", vdoa->irq);
|
||||
return ret;
|
||||
}
|
||||
disable_irq(vdoa->irq);
|
||||
|
||||
vdoa->vdoa_clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(vdoa->vdoa_clk)) {
|
||||
dev_err(dev, "failed to get vdoa_clk\n");
|
||||
return PTR_ERR(vdoa->vdoa_clk);
|
||||
}
|
||||
|
||||
vdoa->iram_pool = of_gen_pool_get(np, "iram", 0);
|
||||
if (!vdoa->iram_pool) {
|
||||
dev_err(&pdev->dev, "iram pool not available\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if ((iram_size == 0) || (iram_size > MAX_VDOA_IRAM_SIZE))
|
||||
iram_size = VDOA_IRAM_SIZE;
|
||||
|
||||
vdoa->iram_base = gen_pool_alloc(vdoa->iram_pool, iram_size);
|
||||
if (!vdoa->iram_base) {
|
||||
dev_err(&pdev->dev, "unable to alloc iram\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
vdoa->iram_paddr = gen_pool_virt_to_phys(vdoa->iram_pool,
|
||||
vdoa->iram_base);
|
||||
|
||||
dev_dbg(dev, "iram_base:0x%lx,iram_paddr:0x%lx,size:0x%lx\n",
|
||||
vdoa->iram_base, vdoa->iram_paddr, iram_size);
|
||||
|
||||
vdoa->state = VDOA_INIT;
|
||||
dev_set_drvdata(dev, vdoa);
|
||||
g_vdoa = vdoa;
|
||||
dev_info(dev, "i.MX Video Data Order Adapter(VDOA) driver probed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vdoa_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct vdoa_info *vdoa = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
gen_pool_free(vdoa->iram_pool, vdoa->iram_base, iram_size);
|
||||
kfree(vdoa);
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver vdoa_driver = {
|
||||
.driver = {
|
||||
.name = "mxc_vdoa",
|
||||
.of_match_table = imx_vdoa_dt_ids,
|
||||
},
|
||||
.probe = vdoa_probe,
|
||||
.remove = vdoa_remove,
|
||||
};
|
||||
|
||||
static int __init vdoa_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = platform_driver_register(&vdoa_driver);
|
||||
if (err) {
|
||||
pr_err("vdoa_driver register failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit vdoa_cleanup(void)
|
||||
{
|
||||
platform_driver_unregister(&vdoa_driver);
|
||||
}
|
||||
|
||||
module_init(vdoa_init);
|
||||
module_exit(vdoa_cleanup);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("i.MX Video Data Order Adapter(VDOA) driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#ifndef __VDOA_H__
|
||||
#define __VDOA_H__
|
||||
|
||||
#define VDOA_PFS_YUYV (1)
|
||||
#define VDOA_PFS_NV12 (0)
|
||||
|
||||
|
||||
struct vfield_buf {
|
||||
u32 prev_veba;
|
||||
u32 cur_veba;
|
||||
u32 next_veba;
|
||||
u32 vubo;
|
||||
};
|
||||
|
||||
struct vframe_buf {
|
||||
u32 veba;
|
||||
u32 vubo;
|
||||
};
|
||||
|
||||
struct vdoa_params {
|
||||
u32 width;
|
||||
u32 height;
|
||||
int vpu_stride;
|
||||
int interlaced;
|
||||
int scan_order;
|
||||
int ipu_num;
|
||||
int band_lines;
|
||||
int band_mode;
|
||||
int pfs;
|
||||
u32 ieba0;
|
||||
u32 ieba1;
|
||||
u32 ieba2;
|
||||
struct vframe_buf vframe_buf;
|
||||
struct vfield_buf vfield_buf;
|
||||
};
|
||||
struct vdoa_ipu_buf {
|
||||
u32 ieba0;
|
||||
u32 ieba1;
|
||||
u32 iubo;
|
||||
};
|
||||
|
||||
struct vdoa_info;
|
||||
typedef void *vdoa_handle_t;
|
||||
|
||||
int vdoa_setup(vdoa_handle_t handle, struct vdoa_params *params);
|
||||
void vdoa_get_output_buf(vdoa_handle_t handle, struct vdoa_ipu_buf *buf);
|
||||
int vdoa_start(vdoa_handle_t handle, int timeout_ms);
|
||||
void vdoa_stop(vdoa_handle_t handle);
|
||||
void vdoa_get_handle(vdoa_handle_t *handle);
|
||||
void vdoa_put_handle(vdoa_handle_t *handle);
|
||||
#endif
|
|
@ -1,29 +1,58 @@
|
|||
config FB_MXC
|
||||
tristate "MXC Framebuffer support"
|
||||
depends on FB
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
select FB_MODE_HELPERS
|
||||
default y
|
||||
help
|
||||
This is a framebuffer device for the MXC LCD Controller.
|
||||
See <http://www.linux-fbdev.org/> for information on framebuffer
|
||||
devices.
|
||||
tristate "MXC Framebuffer support"
|
||||
depends on FB
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
select FB_MODE_HELPERS
|
||||
default y
|
||||
help
|
||||
This is a framebuffer device for the MXC LCD Controller.
|
||||
See <http://www.linux-fbdev.org/> for information on framebuffer
|
||||
devices.
|
||||
|
||||
If you plan to use the LCD display with your MXC system, say
|
||||
Y here.
|
||||
If you plan to use the LCD display with your MXC system, say
|
||||
Y here.
|
||||
|
||||
config FB_MXC_SYNC_PANEL
|
||||
depends on FB_MXC
|
||||
tristate "Synchronous Panel Framebuffer"
|
||||
depends on FB_MXC
|
||||
depends on MXC_IPU_V3
|
||||
tristate "Synchronous Panel Framebuffer"
|
||||
|
||||
config FB_MXC_MIPI_DSI_SAMSUNG
|
||||
tristate "MXC MIPI_DSI_SAMSUNG"
|
||||
depends on FB_MXC_SYNC_PANEL
|
||||
depends on FB_MXS
|
||||
tristate "MXC MIPI_DSI_SAMSUNG"
|
||||
depends on FB_MXC_SYNC_PANEL
|
||||
depends on FB_MXS
|
||||
|
||||
config FB_MXC_TRULY_WVGA_SYNC_PANEL
|
||||
tristate "TRULY WVGA Panel"
|
||||
depends on FB_MXC_SYNC_PANEL
|
||||
depends on FB_MXC_MIPI_DSI_SAMSUNG
|
||||
tristate "TRULY WVGA Panel"
|
||||
depends on FB_MXC_SYNC_PANEL
|
||||
depends on FB_MXC_MIPI_DSI_SAMSUNG
|
||||
|
||||
config FB_MXC_LDB
|
||||
tristate "MXC LDB"
|
||||
depends on FB_MXC_SYNC_PANEL
|
||||
depends on MXC_IPU_V3 || FB_MXS
|
||||
select VIDEOMODE_HELPERS
|
||||
|
||||
config FB_MXC_HDMI
|
||||
depends on FB_MXC_SYNC_PANEL
|
||||
depends on MXC_IPU_V3
|
||||
depends on I2C
|
||||
tristate "MXC HDMI driver support"
|
||||
select MFD_MXC_HDMI
|
||||
help
|
||||
Driver for the on-chip MXC HDMI controller.
|
||||
|
||||
config FB_MXC_EDID
|
||||
depends on FB_MXC && I2C
|
||||
tristate "MXC EDID support"
|
||||
default y
|
||||
|
||||
config HANNSTAR_CABC
|
||||
tristate "Hannstar CABC function"
|
||||
help
|
||||
Say yes here to support switching on/off Hannstar CABC
|
||||
function. This function turns backlight density of a
|
||||
display panel automatically according to the content
|
||||
shown on the panel.
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_dispdrv.o
|
||||
obj-$(CONFIG_FB_MXC_MIPI_DSI_SAMSUNG) += mipi_dsi_samsung.o
|
||||
obj-$(CONFIG_FB_MXC_TRULY_WVGA_SYNC_PANEL) += mxcfb_hx8369_wvga.o
|
||||
obj-$(CONFIG_FB_MXC_LDB) += ldb.o
|
||||
obj-$(CONFIG_FB_MXC_HDMI) += mxc_hdmi.o
|
||||
obj-$(CONFIG_FB_MXC_EDID) += mxc_edid.o
|
||||
obj-$(CONFIG_FB_MXC_SYNC_PANEL) += mxc_dispdrv.o mxc_lcdif.o mxc_ipuv3_fb.o
|
||||
obj-$(CONFIG_FB_MXS_SII902X) += mxsfb_sii902x.o
|
||||
obj-$(CONFIG_HANNSTAR_CABC) += hannstar_cabc.o
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define DRIVER_NAME "hannstar-cabc"
|
||||
|
||||
static const struct of_device_id cabc_dt_ids[] = {
|
||||
{ .compatible = "hannstar,cabc", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cabc_dt_ids);
|
||||
|
||||
static int cabc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node, *pp;
|
||||
int cabc_gpio, ret = 0;
|
||||
bool cabc_enable;
|
||||
unsigned long gpio_flag;
|
||||
enum of_gpio_flags flags;
|
||||
|
||||
for_each_child_of_node(np, pp) {
|
||||
if (!of_find_property(pp, "gpios", NULL)) {
|
||||
dev_warn(&pdev->dev, "Found interface without "
|
||||
"gpios\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
cabc_gpio = of_get_gpio_flags(pp, 0, &flags);
|
||||
if (!gpio_is_valid(cabc_gpio)) {
|
||||
ret = cabc_gpio;
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to get gpio flags, "
|
||||
"error: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cabc_enable = of_property_read_bool(pp, "cabc-enable");
|
||||
|
||||
if (flags & OF_GPIO_ACTIVE_LOW)
|
||||
gpio_flag = cabc_enable ?
|
||||
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH;
|
||||
else
|
||||
gpio_flag = cabc_enable ?
|
||||
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
|
||||
|
||||
devm_gpio_request_one(&pdev->dev, cabc_gpio,
|
||||
gpio_flag, "hannstar-cabc");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver cabc_driver = {
|
||||
.probe = cabc_probe,
|
||||
.driver = {
|
||||
.of_match_table = cabc_dt_ids,
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
module_platform_driver(cabc_driver);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("Hannstar CABC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
|
@ -0,0 +1,913 @@
|
|||
/*
|
||||
* Copyright (C) 2012-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
#include <video/of_videomode.h>
|
||||
#include <video/videomode.h>
|
||||
#include "mxc_dispdrv.h"
|
||||
|
||||
#define DRIVER_NAME "ldb"
|
||||
|
||||
#define LDB_BGREF_RMODE_INT (0x1 << 15)
|
||||
|
||||
#define LDB_DI1_VS_POL_ACT_LOW (0x1 << 10)
|
||||
#define LDB_DI0_VS_POL_ACT_LOW (0x1 << 9)
|
||||
|
||||
#define LDB_BIT_MAP_CH1_JEIDA (0x1 << 8)
|
||||
#define LDB_BIT_MAP_CH0_JEIDA (0x1 << 6)
|
||||
|
||||
#define LDB_DATA_WIDTH_CH1_24 (0x1 << 7)
|
||||
#define LDB_DATA_WIDTH_CH0_24 (0x1 << 5)
|
||||
|
||||
#define LDB_CH1_MODE_MASK (0x3 << 2)
|
||||
#define LDB_CH1_MODE_EN_TO_DI1 (0x3 << 2)
|
||||
#define LDB_CH1_MODE_EN_TO_DI0 (0x1 << 2)
|
||||
#define LDB_CH0_MODE_MASK (0x3 << 0)
|
||||
#define LDB_CH0_MODE_EN_TO_DI1 (0x3 << 0)
|
||||
#define LDB_CH0_MODE_EN_TO_DI0 (0x1 << 0)
|
||||
|
||||
#define LDB_SPLIT_MODE_EN (0x1 << 4)
|
||||
|
||||
#define INVALID_BUS_REG (~0UL)
|
||||
|
||||
struct crtc_mux {
|
||||
enum crtc crtc;
|
||||
u32 val;
|
||||
};
|
||||
|
||||
struct bus_mux {
|
||||
int reg;
|
||||
int shift;
|
||||
int mask;
|
||||
int crtc_mux_num;
|
||||
const struct crtc_mux *crtcs;
|
||||
};
|
||||
|
||||
struct ldb_info {
|
||||
bool split_cap;
|
||||
bool dual_cap;
|
||||
bool ext_bgref_cap;
|
||||
bool clk_fixup;
|
||||
int ctrl_reg;
|
||||
int bus_mux_num;
|
||||
const struct bus_mux *buses;
|
||||
};
|
||||
|
||||
struct ldb_data;
|
||||
|
||||
struct ldb_chan {
|
||||
struct ldb_data *ldb;
|
||||
struct fb_info *fbi;
|
||||
struct videomode vm;
|
||||
enum crtc crtc;
|
||||
int chno;
|
||||
bool is_used;
|
||||
bool online;
|
||||
};
|
||||
|
||||
struct ldb_data {
|
||||
struct regmap *regmap;
|
||||
struct device *dev;
|
||||
struct mxc_dispdrv_handle *mddh;
|
||||
struct ldb_chan chan[2];
|
||||
int bus_mux_num;
|
||||
const struct bus_mux *buses;
|
||||
int primary_chno;
|
||||
int ctrl_reg;
|
||||
u32 ctrl;
|
||||
bool spl_mode;
|
||||
bool dual_mode;
|
||||
bool clk_fixup;
|
||||
struct clk *di_clk[4];
|
||||
struct clk *ldb_di_clk[2];
|
||||
struct clk *div_3_5_clk[2];
|
||||
struct clk *div_7_clk[2];
|
||||
struct clk *div_sel_clk[2];
|
||||
};
|
||||
|
||||
static const struct crtc_mux imx6q_lvds0_crtc_mux[] = {
|
||||
{
|
||||
.crtc = CRTC_IPU1_DI0,
|
||||
.val = IMX6Q_GPR3_LVDS0_MUX_CTL_IPU1_DI0,
|
||||
}, {
|
||||
.crtc = CRTC_IPU1_DI1,
|
||||
.val = IMX6Q_GPR3_LVDS0_MUX_CTL_IPU1_DI1,
|
||||
}, {
|
||||
.crtc = CRTC_IPU2_DI0,
|
||||
.val = IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI0,
|
||||
}, {
|
||||
.crtc = CRTC_IPU2_DI1,
|
||||
.val = IMX6Q_GPR3_LVDS0_MUX_CTL_IPU2_DI1,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct crtc_mux imx6q_lvds1_crtc_mux[] = {
|
||||
{
|
||||
.crtc = CRTC_IPU1_DI0,
|
||||
.val = IMX6Q_GPR3_LVDS1_MUX_CTL_IPU1_DI0,
|
||||
}, {
|
||||
.crtc = CRTC_IPU1_DI1,
|
||||
.val = IMX6Q_GPR3_LVDS1_MUX_CTL_IPU1_DI1,
|
||||
}, {
|
||||
.crtc = CRTC_IPU2_DI0,
|
||||
.val = IMX6Q_GPR3_LVDS1_MUX_CTL_IPU2_DI0,
|
||||
}, {
|
||||
.crtc = CRTC_IPU2_DI1,
|
||||
.val = IMX6Q_GPR3_LVDS1_MUX_CTL_IPU2_DI1,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct bus_mux imx6q_ldb_buses[] = {
|
||||
{
|
||||
.reg = IOMUXC_GPR3,
|
||||
.shift = 6,
|
||||
.mask = IMX6Q_GPR3_LVDS0_MUX_CTL_MASK,
|
||||
.crtc_mux_num = ARRAY_SIZE(imx6q_lvds0_crtc_mux),
|
||||
.crtcs = imx6q_lvds0_crtc_mux,
|
||||
}, {
|
||||
.reg = IOMUXC_GPR3,
|
||||
.shift = 8,
|
||||
.mask = IMX6Q_GPR3_LVDS1_MUX_CTL_MASK,
|
||||
.crtc_mux_num = ARRAY_SIZE(imx6q_lvds1_crtc_mux),
|
||||
.crtcs = imx6q_lvds1_crtc_mux,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ldb_info imx6q_ldb_info = {
|
||||
.split_cap = true,
|
||||
.dual_cap = true,
|
||||
.ext_bgref_cap = false,
|
||||
.clk_fixup = false,
|
||||
.ctrl_reg = IOMUXC_GPR2,
|
||||
.bus_mux_num = ARRAY_SIZE(imx6q_ldb_buses),
|
||||
.buses = imx6q_ldb_buses,
|
||||
};
|
||||
|
||||
static const struct ldb_info imx6qp_ldb_info = {
|
||||
.split_cap = true,
|
||||
.dual_cap = true,
|
||||
.ext_bgref_cap = false,
|
||||
.clk_fixup = true,
|
||||
.ctrl_reg = IOMUXC_GPR2,
|
||||
.bus_mux_num = ARRAY_SIZE(imx6q_ldb_buses),
|
||||
.buses = imx6q_ldb_buses,
|
||||
};
|
||||
|
||||
static const struct crtc_mux imx6dl_lvds0_crtc_mux[] = {
|
||||
{
|
||||
.crtc = CRTC_IPU1_DI0,
|
||||
.val = IMX6DL_GPR3_LVDS0_MUX_CTL_IPU1_DI0,
|
||||
}, {
|
||||
.crtc = CRTC_IPU1_DI1,
|
||||
.val = IMX6DL_GPR3_LVDS0_MUX_CTL_IPU1_DI1,
|
||||
}, {
|
||||
.crtc = CRTC_LCDIF1,
|
||||
.val = IMX6DL_GPR3_LVDS0_MUX_CTL_LCDIF,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct crtc_mux imx6dl_lvds1_crtc_mux[] = {
|
||||
{
|
||||
.crtc = CRTC_IPU1_DI0,
|
||||
.val = IMX6DL_GPR3_LVDS1_MUX_CTL_IPU1_DI0,
|
||||
}, {
|
||||
.crtc = CRTC_IPU1_DI1,
|
||||
.val = IMX6DL_GPR3_LVDS1_MUX_CTL_IPU1_DI1,
|
||||
}, {
|
||||
.crtc = CRTC_LCDIF1,
|
||||
.val = IMX6DL_GPR3_LVDS1_MUX_CTL_LCDIF,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct bus_mux imx6dl_ldb_buses[] = {
|
||||
{
|
||||
.reg = IOMUXC_GPR3,
|
||||
.shift = 6,
|
||||
.mask = IMX6DL_GPR3_LVDS0_MUX_CTL_MASK,
|
||||
.crtc_mux_num = ARRAY_SIZE(imx6dl_lvds0_crtc_mux),
|
||||
.crtcs = imx6dl_lvds0_crtc_mux,
|
||||
}, {
|
||||
.reg = IOMUXC_GPR3,
|
||||
.shift = 8,
|
||||
.mask = IMX6DL_GPR3_LVDS1_MUX_CTL_MASK,
|
||||
.crtc_mux_num = ARRAY_SIZE(imx6dl_lvds1_crtc_mux),
|
||||
.crtcs = imx6dl_lvds1_crtc_mux,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ldb_info imx6dl_ldb_info = {
|
||||
.split_cap = true,
|
||||
.dual_cap = true,
|
||||
.ext_bgref_cap = false,
|
||||
.clk_fixup = false,
|
||||
.ctrl_reg = IOMUXC_GPR2,
|
||||
.bus_mux_num = ARRAY_SIZE(imx6dl_ldb_buses),
|
||||
.buses = imx6dl_ldb_buses,
|
||||
};
|
||||
|
||||
static const struct crtc_mux imx6sx_lvds_crtc_mux[] = {
|
||||
{
|
||||
.crtc = CRTC_LCDIF1,
|
||||
.val = IMX6SX_GPR5_DISP_MUX_LDB_CTRL_LCDIF1,
|
||||
}, {
|
||||
.crtc = CRTC_LCDIF2,
|
||||
.val = IMX6SX_GPR5_DISP_MUX_LDB_CTRL_LCDIF2,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct bus_mux imx6sx_ldb_buses[] = {
|
||||
{
|
||||
.reg = IOMUXC_GPR5,
|
||||
.shift = 3,
|
||||
.mask = IMX6SX_GPR5_DISP_MUX_LDB_CTRL_MASK,
|
||||
.crtc_mux_num = ARRAY_SIZE(imx6sx_lvds_crtc_mux),
|
||||
.crtcs = imx6sx_lvds_crtc_mux,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ldb_info imx6sx_ldb_info = {
|
||||
.split_cap = false,
|
||||
.dual_cap = false,
|
||||
.ext_bgref_cap = false,
|
||||
.clk_fixup = false,
|
||||
.ctrl_reg = IOMUXC_GPR6,
|
||||
.bus_mux_num = ARRAY_SIZE(imx6sx_ldb_buses),
|
||||
.buses = imx6sx_ldb_buses,
|
||||
};
|
||||
|
||||
static const struct crtc_mux imx53_lvds0_crtc_mux[] = {
|
||||
{ .crtc = CRTC_IPU1_DI0, },
|
||||
};
|
||||
|
||||
static const struct crtc_mux imx53_lvds1_crtc_mux[] = {
|
||||
{ .crtc = CRTC_IPU1_DI1, }
|
||||
};
|
||||
|
||||
static const struct bus_mux imx53_ldb_buses[] = {
|
||||
{
|
||||
.reg = INVALID_BUS_REG,
|
||||
.crtc_mux_num = ARRAY_SIZE(imx53_lvds0_crtc_mux),
|
||||
.crtcs = imx53_lvds0_crtc_mux,
|
||||
}, {
|
||||
.reg = INVALID_BUS_REG,
|
||||
.crtc_mux_num = ARRAY_SIZE(imx53_lvds1_crtc_mux),
|
||||
.crtcs = imx53_lvds1_crtc_mux,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ldb_info imx53_ldb_info = {
|
||||
.split_cap = true,
|
||||
.dual_cap = false,
|
||||
.ext_bgref_cap = true,
|
||||
.clk_fixup = false,
|
||||
.ctrl_reg = IOMUXC_GPR2,
|
||||
.bus_mux_num = ARRAY_SIZE(imx53_ldb_buses),
|
||||
.buses = imx53_ldb_buses,
|
||||
};
|
||||
|
||||
static const struct of_device_id ldb_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx6qp-ldb", .data = &imx6qp_ldb_info, },
|
||||
{ .compatible = "fsl,imx6q-ldb", .data = &imx6q_ldb_info, },
|
||||
{ .compatible = "fsl,imx6dl-ldb", .data = &imx6dl_ldb_info, },
|
||||
{ .compatible = "fsl,imx6sx-ldb", .data = &imx6sx_ldb_info, },
|
||||
{ .compatible = "fsl,imx53-ldb", .data = &imx53_ldb_info, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ldb_dt_ids);
|
||||
|
||||
static int ldb_init(struct mxc_dispdrv_handle *mddh,
|
||||
struct mxc_dispdrv_setting *setting)
|
||||
{
|
||||
struct ldb_data *ldb = mxc_dispdrv_getdata(mddh);
|
||||
struct device *dev = ldb->dev;
|
||||
struct fb_info *fbi = setting->fbi;
|
||||
struct ldb_chan *chan;
|
||||
struct fb_videomode fb_vm;
|
||||
int chno;
|
||||
|
||||
chno = ldb->chan[ldb->primary_chno].is_used ?
|
||||
!ldb->primary_chno : ldb->primary_chno;
|
||||
|
||||
chan = &ldb->chan[chno];
|
||||
|
||||
if (chan->is_used) {
|
||||
dev_err(dev, "LVDS channel%d is already used\n", chno);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (!chan->online) {
|
||||
dev_err(dev, "LVDS channel%d is not online\n", chno);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
chan->is_used = true;
|
||||
|
||||
chan->fbi = fbi;
|
||||
|
||||
fb_videomode_from_videomode(&chan->vm, &fb_vm);
|
||||
|
||||
INIT_LIST_HEAD(&fbi->modelist);
|
||||
fb_add_videomode(&fb_vm, &fbi->modelist);
|
||||
fb_videomode_to_var(&fbi->var, &fb_vm);
|
||||
|
||||
setting->crtc = chan->crtc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_di_clk_id(struct ldb_chan chan, int *id)
|
||||
{
|
||||
struct ldb_data *ldb = chan.ldb;
|
||||
int i = 0, chno = chan.chno, mask, shift;
|
||||
enum crtc crtc;
|
||||
u32 val;
|
||||
|
||||
/* no pre-muxing, such as mx53 */
|
||||
if (ldb->buses[chno].reg == INVALID_BUS_REG) {
|
||||
*id = chno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (; i < ldb->buses[chno].crtc_mux_num; i++) {
|
||||
crtc = ldb->buses[chno].crtcs[i].crtc;
|
||||
val = ldb->buses[chno].crtcs[i].val;
|
||||
mask = ldb->buses[chno].mask;
|
||||
shift = ldb->buses[chno].shift;
|
||||
if (chan.crtc == crtc) {
|
||||
*id = (val & mask) >> shift;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int get_mux_val(struct bus_mux bus_mux, enum crtc crtc,
|
||||
u32 *mux_val)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (; i < bus_mux.crtc_mux_num; i++)
|
||||
if (bus_mux.crtcs[i].crtc == crtc) {
|
||||
*mux_val = bus_mux.crtcs[i].val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int find_ldb_chno(struct ldb_data *ldb,
|
||||
struct fb_info *fbi, int *chno)
|
||||
{
|
||||
struct device *dev = ldb->dev;
|
||||
int i = 0;
|
||||
|
||||
for (; i < 2; i++)
|
||||
if (ldb->chan[i].fbi == fbi) {
|
||||
*chno = ldb->chan[i].chno;
|
||||
return 0;
|
||||
}
|
||||
dev_err(dev, "failed to find channel number\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void ldb_disable(struct mxc_dispdrv_handle *mddh,
|
||||
struct fb_info *fbi);
|
||||
|
||||
static int ldb_setup(struct mxc_dispdrv_handle *mddh,
|
||||
struct fb_info *fbi)
|
||||
{
|
||||
struct ldb_data *ldb = mxc_dispdrv_getdata(mddh);
|
||||
struct ldb_chan chan;
|
||||
struct device *dev = ldb->dev;
|
||||
struct clk *ldb_di_parent, *ldb_di_sel, *ldb_di_sel_parent;
|
||||
struct clk *other_ldb_di_sel = NULL;
|
||||
struct bus_mux bus_mux;
|
||||
int ret = 0, id = 0, chno, other_chno;
|
||||
unsigned long serial_clk;
|
||||
u32 mux_val;
|
||||
|
||||
ret = find_ldb_chno(ldb, fbi, &chno);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
other_chno = chno ? 0 : 1;
|
||||
|
||||
chan = ldb->chan[chno];
|
||||
|
||||
bus_mux = ldb->buses[chno];
|
||||
|
||||
ret = get_di_clk_id(chan, &id);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to get ch%d di clk id\n",
|
||||
chan.chno);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = get_mux_val(bus_mux, chan.crtc, &mux_val);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to get ch%d mux val\n",
|
||||
chan.chno);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
if (ldb->clk_fixup) {
|
||||
/*
|
||||
* ldb_di_sel_parent(plls) -> ldb_di_sel -> ldb_di[chno] ->
|
||||
*
|
||||
* -> div_3_5[chno] ->
|
||||
* -> | |-> div_sel[chno] -> di[id]
|
||||
* -> div_7[chno] ->
|
||||
*/
|
||||
clk_set_parent(ldb->di_clk[id], ldb->div_sel_clk[chno]);
|
||||
} else {
|
||||
/*
|
||||
* ldb_di_sel_parent(plls) -> ldb_di_sel ->
|
||||
*
|
||||
* -> div_3_5[chno] ->
|
||||
* -> | |-> div_sel[chno] ->
|
||||
* -> div_7[chno] ->
|
||||
*
|
||||
* -> ldb_di[chno] -> di[id]
|
||||
*/
|
||||
clk_set_parent(ldb->di_clk[id], ldb->ldb_di_clk[chno]);
|
||||
}
|
||||
ldb_di_parent = ldb->spl_mode ? ldb->div_3_5_clk[chno] :
|
||||
ldb->div_7_clk[chno];
|
||||
clk_set_parent(ldb->div_sel_clk[chno], ldb_di_parent);
|
||||
ldb_di_sel = clk_get_parent(ldb_di_parent);
|
||||
ldb_di_sel_parent = clk_get_parent(ldb_di_sel);
|
||||
serial_clk = ldb->spl_mode ? chan.vm.pixelclock * 7 / 2 :
|
||||
chan.vm.pixelclock * 7;
|
||||
clk_set_rate(ldb_di_sel_parent, serial_clk);
|
||||
|
||||
/*
|
||||
* split mode or dual mode:
|
||||
* clock tree for the other channel
|
||||
*/
|
||||
if (ldb->spl_mode) {
|
||||
clk_set_parent(ldb->div_sel_clk[other_chno],
|
||||
ldb->div_3_5_clk[other_chno]);
|
||||
other_ldb_di_sel =
|
||||
clk_get_parent(ldb->div_3_5_clk[other_chno]);;
|
||||
}
|
||||
|
||||
if (ldb->dual_mode) {
|
||||
clk_set_parent(ldb->div_sel_clk[other_chno],
|
||||
ldb->div_7_clk[other_chno]);
|
||||
other_ldb_di_sel =
|
||||
clk_get_parent(ldb->div_7_clk[other_chno]);;
|
||||
}
|
||||
|
||||
if (ldb->spl_mode || ldb->dual_mode)
|
||||
clk_set_parent(other_ldb_di_sel, ldb_di_sel_parent);
|
||||
|
||||
if (!(chan.fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)) {
|
||||
if (ldb->spl_mode && bus_mux.reg == INVALID_BUS_REG)
|
||||
/* no pre-muxing, such as mx53 */
|
||||
ldb->ctrl |= (id == 0 ? LDB_DI0_VS_POL_ACT_LOW :
|
||||
LDB_DI1_VS_POL_ACT_LOW);
|
||||
else
|
||||
ldb->ctrl |= (chno == 0 ? LDB_DI0_VS_POL_ACT_LOW :
|
||||
LDB_DI1_VS_POL_ACT_LOW);
|
||||
}
|
||||
|
||||
if (bus_mux.reg != INVALID_BUS_REG)
|
||||
regmap_update_bits(ldb->regmap, bus_mux.reg,
|
||||
bus_mux.mask, mux_val);
|
||||
|
||||
regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ctrl);
|
||||
|
||||
/* disable channel for correct sequence */
|
||||
ldb_disable(mddh, fbi);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ldb_enable(struct mxc_dispdrv_handle *mddh,
|
||||
struct fb_info *fbi)
|
||||
{
|
||||
struct ldb_data *ldb = mxc_dispdrv_getdata(mddh);
|
||||
struct ldb_chan chan;
|
||||
struct device *dev = ldb->dev;
|
||||
struct bus_mux bus_mux;
|
||||
int ret = 0, id = 0, chno, other_chno;
|
||||
|
||||
ret = find_ldb_chno(ldb, fbi, &chno);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
chan = ldb->chan[chno];
|
||||
|
||||
bus_mux = ldb->buses[chno];
|
||||
|
||||
if (ldb->spl_mode || ldb->dual_mode) {
|
||||
other_chno = chno ? 0 : 1;
|
||||
clk_prepare_enable(ldb->ldb_di_clk[other_chno]);
|
||||
}
|
||||
|
||||
if ((ldb->spl_mode || ldb->dual_mode) &&
|
||||
bus_mux.reg == INVALID_BUS_REG) {
|
||||
/* no pre-muxing, such as mx53 */
|
||||
ret = get_di_clk_id(chan, &id);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to get ch%d di clk id\n",
|
||||
chan.chno);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ldb->ctrl |= id ?
|
||||
(LDB_CH0_MODE_EN_TO_DI1 | LDB_CH1_MODE_EN_TO_DI1) :
|
||||
(LDB_CH0_MODE_EN_TO_DI0 | LDB_CH1_MODE_EN_TO_DI0);
|
||||
} else {
|
||||
if (ldb->spl_mode || ldb->dual_mode)
|
||||
ldb->ctrl |= LDB_CH0_MODE_EN_TO_DI0 |
|
||||
LDB_CH1_MODE_EN_TO_DI0;
|
||||
else
|
||||
ldb->ctrl |= chno ? LDB_CH1_MODE_EN_TO_DI1 :
|
||||
LDB_CH0_MODE_EN_TO_DI0;
|
||||
}
|
||||
|
||||
regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ldb_disable(struct mxc_dispdrv_handle *mddh,
|
||||
struct fb_info *fbi)
|
||||
{
|
||||
struct ldb_data *ldb = mxc_dispdrv_getdata(mddh);
|
||||
int ret, chno, other_chno;
|
||||
|
||||
ret = find_ldb_chno(ldb, fbi, &chno);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
if (ldb->spl_mode || ldb->dual_mode) {
|
||||
ldb->ctrl &= ~(LDB_CH1_MODE_MASK | LDB_CH0_MODE_MASK);
|
||||
other_chno = chno ? 0 : 1;
|
||||
clk_disable_unprepare(ldb->ldb_di_clk[other_chno]);
|
||||
} else {
|
||||
ldb->ctrl &= ~(chno ? LDB_CH1_MODE_MASK :
|
||||
LDB_CH0_MODE_MASK);
|
||||
}
|
||||
|
||||
regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ctrl);
|
||||
return;
|
||||
}
|
||||
|
||||
static struct mxc_dispdrv_driver ldb_drv = {
|
||||
.name = DRIVER_NAME,
|
||||
.init = ldb_init,
|
||||
.setup = ldb_setup,
|
||||
.enable = ldb_enable,
|
||||
.disable = ldb_disable
|
||||
};
|
||||
|
||||
enum {
|
||||
LVDS_BIT_MAP_SPWG,
|
||||
LVDS_BIT_MAP_JEIDA,
|
||||
};
|
||||
|
||||
static const char *ldb_bit_mappings[] = {
|
||||
[LVDS_BIT_MAP_SPWG] = "spwg",
|
||||
[LVDS_BIT_MAP_JEIDA] = "jeida",
|
||||
};
|
||||
|
||||
static int of_get_data_mapping(struct device_node *np)
|
||||
{
|
||||
const char *bm;
|
||||
int ret, i;
|
||||
|
||||
ret = of_property_read_string(np, "fsl,data-mapping", &bm);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ldb_bit_mappings); i++)
|
||||
if (!strcasecmp(bm, ldb_bit_mappings[i]))
|
||||
return i;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const char *ldb_crtc_mappings[] = {
|
||||
[CRTC_IPU_DI0] = "ipu-di0",
|
||||
[CRTC_IPU_DI1] = "ipu-di1",
|
||||
[CRTC_IPU1_DI0] = "ipu1-di0",
|
||||
[CRTC_IPU1_DI1] = "ipu1-di1",
|
||||
[CRTC_IPU2_DI0] = "ipu2-di0",
|
||||
[CRTC_IPU2_DI1] = "ipu2-di1",
|
||||
[CRTC_LCDIF] = "lcdif",
|
||||
[CRTC_LCDIF1] = "lcdif1",
|
||||
[CRTC_LCDIF2] = "lcdif2",
|
||||
};
|
||||
|
||||
static enum crtc of_get_crtc_mapping(struct device_node *np)
|
||||
{
|
||||
const char *cm;
|
||||
enum crtc i;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_string(np, "crtc", &cm);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ldb_crtc_mappings); i++)
|
||||
if (!strcasecmp(cm, ldb_crtc_mappings[i])) {
|
||||
switch (i) {
|
||||
case CRTC_IPU_DI0:
|
||||
i = CRTC_IPU1_DI0;
|
||||
break;
|
||||
case CRTC_IPU_DI1:
|
||||
i = CRTC_IPU1_DI1;
|
||||
break;
|
||||
case CRTC_LCDIF:
|
||||
i = CRTC_LCDIF1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int mux_count(struct ldb_data *ldb)
|
||||
{
|
||||
int i, j, count = 0;
|
||||
bool should_count[CRTC_MAX];
|
||||
enum crtc crtc;
|
||||
|
||||
for (i = 0; i < CRTC_MAX; i++)
|
||||
should_count[i] = true;
|
||||
|
||||
for (i = 0; i < ldb->bus_mux_num; i++) {
|
||||
for (j = 0; j < ldb->buses[i].crtc_mux_num; j++) {
|
||||
crtc = ldb->buses[i].crtcs[j].crtc;
|
||||
if (should_count[crtc]) {
|
||||
count++;
|
||||
should_count[crtc] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static bool is_valid_crtc(struct ldb_data *ldb, enum crtc crtc,
|
||||
int chno)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (chno > ldb->bus_mux_num - 1)
|
||||
return false;
|
||||
|
||||
for (; i < ldb->buses[chno].crtc_mux_num; i++)
|
||||
if (ldb->buses[chno].crtcs[i].crtc == crtc)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int ldb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(ldb_dt_ids, dev);
|
||||
const struct ldb_info *ldb_info =
|
||||
(const struct ldb_info *)of_id->data;
|
||||
struct device_node *np = dev->of_node, *child;
|
||||
struct ldb_data *ldb;
|
||||
bool ext_ref;
|
||||
int i, data_width, mapping, child_count = 0;
|
||||
char clkname[16];
|
||||
|
||||
ldb = devm_kzalloc(dev, sizeof(*ldb), GFP_KERNEL);
|
||||
if (!ldb)
|
||||
return -ENOMEM;
|
||||
|
||||
ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
|
||||
if (IS_ERR(ldb->regmap)) {
|
||||
dev_err(dev, "failed to get parent regmap\n");
|
||||
return PTR_ERR(ldb->regmap);
|
||||
}
|
||||
|
||||
ldb->dev = dev;
|
||||
ldb->bus_mux_num = ldb_info->bus_mux_num;
|
||||
ldb->buses = ldb_info->buses;
|
||||
ldb->ctrl_reg = ldb_info->ctrl_reg;
|
||||
ldb->clk_fixup = ldb_info->clk_fixup;
|
||||
ldb->primary_chno = -1;
|
||||
|
||||
ext_ref = of_property_read_bool(np, "ext-ref");
|
||||
if (!ext_ref && ldb_info->ext_bgref_cap)
|
||||
ldb->ctrl |= LDB_BGREF_RMODE_INT;
|
||||
|
||||
ldb->spl_mode = of_property_read_bool(np, "split-mode");
|
||||
if (ldb->spl_mode) {
|
||||
if (ldb_info->split_cap) {
|
||||
ldb->ctrl |= LDB_SPLIT_MODE_EN;
|
||||
dev_info(dev, "split mode\n");
|
||||
} else {
|
||||
dev_err(dev, "cannot support split mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
ldb->dual_mode = of_property_read_bool(np, "dual-mode");
|
||||
if (ldb->dual_mode) {
|
||||
if (ldb_info->dual_cap) {
|
||||
dev_info(dev, "dual mode\n");
|
||||
} else {
|
||||
dev_err(dev, "cannot support dual mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (ldb->dual_mode && ldb->spl_mode) {
|
||||
dev_err(dev, "cannot support dual mode and split mode "
|
||||
"simultaneously\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < mux_count(ldb); i++) {
|
||||
sprintf(clkname, "di%d_sel", i);
|
||||
ldb->di_clk[i] = devm_clk_get(dev, clkname);
|
||||
if (IS_ERR(ldb->di_clk[i])) {
|
||||
dev_err(dev, "failed to get clk %s\n", clkname);
|
||||
return PTR_ERR(ldb->di_clk[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for_each_child_of_node(np, child) {
|
||||
struct ldb_chan *chan;
|
||||
enum crtc crtc;
|
||||
bool is_primary;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(child, "reg", &i);
|
||||
if (ret || i < 0 || i > 1 || i >= ldb->bus_mux_num) {
|
||||
dev_err(dev, "wrong LVDS channel number\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((ldb->spl_mode || ldb->dual_mode) && i > 0) {
|
||||
dev_warn(dev, "split mode or dual mode, ignoring "
|
||||
"second output\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!of_device_is_available(child))
|
||||
continue;
|
||||
|
||||
if (++child_count > ldb->bus_mux_num) {
|
||||
dev_err(dev, "too many LVDS channels\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chan = &ldb->chan[i];
|
||||
chan->chno = i;
|
||||
chan->ldb = ldb;
|
||||
chan->online = true;
|
||||
|
||||
is_primary = of_property_read_bool(child, "primary");
|
||||
|
||||
if (ldb->bus_mux_num == 1 || (ldb->primary_chno == -1 &&
|
||||
(is_primary || ldb->spl_mode || ldb->dual_mode)))
|
||||
ldb->primary_chno = chan->chno;
|
||||
|
||||
ret = of_property_read_u32(child, "fsl,data-width",
|
||||
&data_width);
|
||||
if (ret || (data_width != 18 && data_width != 24)) {
|
||||
dev_err(dev, "data width not specified or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mapping = of_get_data_mapping(child);
|
||||
switch (mapping) {
|
||||
case LVDS_BIT_MAP_SPWG:
|
||||
if (data_width == 24) {
|
||||
if (i == 0 || ldb->spl_mode || ldb->dual_mode)
|
||||
ldb->ctrl |= LDB_DATA_WIDTH_CH0_24;
|
||||
if (i == 1 || ldb->spl_mode || ldb->dual_mode)
|
||||
ldb->ctrl |= LDB_DATA_WIDTH_CH1_24;
|
||||
}
|
||||
break;
|
||||
case LVDS_BIT_MAP_JEIDA:
|
||||
if (data_width == 18) {
|
||||
dev_err(dev, "JEIDA only support 24bit\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (i == 0 || ldb->spl_mode || ldb->dual_mode)
|
||||
ldb->ctrl |= LDB_DATA_WIDTH_CH0_24 |
|
||||
LDB_BIT_MAP_CH0_JEIDA;
|
||||
if (i == 1 || ldb->spl_mode || ldb->dual_mode)
|
||||
ldb->ctrl |= LDB_DATA_WIDTH_CH1_24 |
|
||||
LDB_BIT_MAP_CH1_JEIDA;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "data mapping not specified or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
crtc = of_get_crtc_mapping(child);
|
||||
if (is_valid_crtc(ldb, crtc, chan->chno)) {
|
||||
ldb->chan[i].crtc = crtc;
|
||||
} else {
|
||||
dev_err(dev, "crtc not specified or invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = of_get_videomode(child, &chan->vm, 0);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
sprintf(clkname, "ldb_di%d", i);
|
||||
ldb->ldb_di_clk[i] = devm_clk_get(dev, clkname);
|
||||
if (IS_ERR(ldb->ldb_di_clk[i])) {
|
||||
dev_err(dev, "failed to get clk %s\n", clkname);
|
||||
return PTR_ERR(ldb->ldb_di_clk[i]);
|
||||
}
|
||||
|
||||
sprintf(clkname, "ldb_di%d_div_3_5", i);
|
||||
ldb->div_3_5_clk[i] = devm_clk_get(dev, clkname);
|
||||
if (IS_ERR(ldb->div_3_5_clk[i])) {
|
||||
dev_err(dev, "failed to get clk %s\n", clkname);
|
||||
return PTR_ERR(ldb->div_3_5_clk[i]);
|
||||
}
|
||||
|
||||
sprintf(clkname, "ldb_di%d_div_7", i);
|
||||
ldb->div_7_clk[i] = devm_clk_get(dev, clkname);
|
||||
if (IS_ERR(ldb->div_7_clk[i])) {
|
||||
dev_err(dev, "failed to get clk %s\n", clkname);
|
||||
return PTR_ERR(ldb->div_7_clk[i]);
|
||||
}
|
||||
|
||||
sprintf(clkname, "ldb_di%d_div_sel", i);
|
||||
ldb->div_sel_clk[i] = devm_clk_get(dev, clkname);
|
||||
if (IS_ERR(ldb->div_sel_clk[i])) {
|
||||
dev_err(dev, "failed to get clk %s\n", clkname);
|
||||
return PTR_ERR(ldb->div_sel_clk[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (child_count == 0) {
|
||||
dev_err(dev, "failed to find valid LVDS channel\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ldb->primary_chno == -1) {
|
||||
dev_err(dev, "failed to know primary channel\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ldb->mddh = mxc_dispdrv_register(&ldb_drv);
|
||||
mxc_dispdrv_setdata(ldb->mddh, ldb);
|
||||
dev_set_drvdata(&pdev->dev, ldb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ldb_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ldb_data *ldb = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
mxc_dispdrv_puthandle(ldb->mddh);
|
||||
mxc_dispdrv_unregister(ldb->mddh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ldb_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = ldb_dt_ids,
|
||||
},
|
||||
.probe = ldb_probe,
|
||||
.remove = ldb_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(ldb_driver);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("LDB driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
* Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,769 @@
|
|||
/*
|
||||
* Copyright 2009-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @defgroup Framebuffer Framebuffer Driver for SDC and ADC.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file mxc_edid.c
|
||||
*
|
||||
* @brief MXC EDID driver
|
||||
*
|
||||
* @ingroup Framebuffer
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Include files
|
||||
*/
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/fb.h>
|
||||
#include <video/mxc_edid.h>
|
||||
#include "../edid.h"
|
||||
|
||||
#undef DEBUG /* define this for verbose EDID parsing output */
|
||||
#ifdef DEBUG
|
||||
#define DPRINTK(fmt, args...) printk(fmt, ## args)
|
||||
#else
|
||||
#define DPRINTK(fmt, args...)
|
||||
#endif
|
||||
|
||||
const struct fb_videomode mxc_cea_mode[64] = {
|
||||
/* #1: 640x480p@59.94/60Hz 4:3 */
|
||||
[1] = {
|
||||
NULL, 60, 640, 480, 39722, 48, 16, 33, 10, 96, 2, 0,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
|
||||
},
|
||||
/* #2: 720x480p@59.94/60Hz 4:3 */
|
||||
[2] = {
|
||||
NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
|
||||
},
|
||||
/* #3: 720x480p@59.94/60Hz 16:9 */
|
||||
[3] = {
|
||||
NULL, 60, 720, 480, 37037, 60, 16, 30, 9, 62, 6, 0,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #4: 1280x720p@59.94/60Hz 16:9 */
|
||||
[4] = {
|
||||
NULL, 60, 1280, 720, 13468, 220, 110, 20, 5, 40, 5,
|
||||
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0
|
||||
},
|
||||
/* #5: 1920x1080i@59.94/60Hz 16:9 */
|
||||
[5] = {
|
||||
NULL, 60, 1920, 1080, 13763, 148, 88, 15, 2, 44, 5,
|
||||
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #6: 720(1440)x480iH@59.94/60Hz 4:3 */
|
||||
[6] = {
|
||||
NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0,
|
||||
FB_VMODE_INTERLACED | FB_VMODE_ASPECT_4_3, 0,
|
||||
},
|
||||
/* #7: 720(1440)x480iH@59.94/60Hz 16:9 */
|
||||
[7] = {
|
||||
NULL, 60, 1440, 480, 18554/*37108*/, 114, 38, 15, 4, 124, 3, 0,
|
||||
FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #8: 720(1440)x240pH@59.94/60Hz 4:3 */
|
||||
[8] = {
|
||||
NULL, 60, 1440, 240, 37108, 114, 38, 15, 4, 124, 3, 0,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
|
||||
},
|
||||
/* #9: 720(1440)x240pH@59.94/60Hz 16:9 */
|
||||
[9] = {
|
||||
NULL, 60, 1440, 240, 37108, 114, 38, 15, 4, 124, 3, 0,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #14: 1440x480p@59.94/60Hz 4:3 */
|
||||
[14] = {
|
||||
NULL, 60, 1440, 480, 18500, 120, 32, 30, 9, 124, 6, 0,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
|
||||
},
|
||||
/* #15: 1440x480p@59.94/60Hz 16:9 */
|
||||
[15] = {
|
||||
NULL, 60, 1440, 480, 18500, 120, 32, 30, 9, 124, 6, 0,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #16: 1920x1080p@60Hz 16:9 */
|
||||
[16] = {
|
||||
NULL, 60, 1920, 1080, 6734, 148, 88, 36, 4, 44, 5,
|
||||
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #17: 720x576pH@50Hz 4:3 */
|
||||
[17] = {
|
||||
NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
|
||||
},
|
||||
/* #18: 720x576pH@50Hz 16:9 */
|
||||
[18] = {
|
||||
NULL, 50, 720, 576, 37037, 68, 12, 39, 5, 64, 5, 0,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #19: 1280x720p@50Hz */
|
||||
[19] = {
|
||||
NULL, 50, 1280, 720, 13468, 220, 440, 20, 5, 40, 5,
|
||||
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #20: 1920x1080i@50Hz */
|
||||
[20] = {
|
||||
NULL, 50, 1920, 1080, 13480, 148, 528, 15, 5, 528, 5,
|
||||
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
FB_VMODE_INTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #23: 720(1440)x288pH@50Hz 4:3 */
|
||||
[23] = {
|
||||
NULL, 50, 1440, 288, 37037, 138, 24, 19, 2, 126, 3, 0,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
|
||||
},
|
||||
/* #24: 720(1440)x288pH@50Hz 16:9 */
|
||||
[24] = {
|
||||
NULL, 50, 1440, 288, 37037, 138, 24, 19, 2, 126, 3, 0,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #29: 720(1440)x576pH@50Hz 4:3 */
|
||||
[29] = {
|
||||
NULL, 50, 1440, 576, 18518, 136, 24, 39, 5, 128, 5, 0,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_4_3, 0,
|
||||
},
|
||||
/* #30: 720(1440)x576pH@50Hz 16:9 */
|
||||
[30] = {
|
||||
NULL, 50, 1440, 576, 18518, 136, 24, 39, 5, 128, 5, 0,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #31: 1920x1080p@50Hz */
|
||||
[31] = {
|
||||
NULL, 50, 1920, 1080, 6734, 148, 528, 36, 4, 44, 5,
|
||||
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #32: 1920x1080p@23.98/24Hz */
|
||||
[32] = {
|
||||
NULL, 24, 1920, 1080, 13468, 148, 638, 36, 4, 44, 5,
|
||||
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #33: 1920x1080p@25Hz */
|
||||
[33] = {
|
||||
NULL, 25, 1920, 1080, 13468, 148, 528, 36, 4, 44, 5,
|
||||
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #34: 1920x1080p@30Hz */
|
||||
[34] = {
|
||||
NULL, 30, 1920, 1080, 13468, 148, 88, 36, 4, 44, 5,
|
||||
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0,
|
||||
},
|
||||
/* #41: 1280x720p@100Hz 16:9 */
|
||||
[41] = {
|
||||
NULL, 100, 1280, 720, 6734, 220, 440, 20, 5, 40, 5,
|
||||
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0
|
||||
},
|
||||
/* #47: 1280x720p@119.88/120Hz 16:9 */
|
||||
[47] = {
|
||||
NULL, 120, 1280, 720, 6734, 220, 110, 20, 5, 40, 5,
|
||||
FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
FB_VMODE_NONINTERLACED | FB_VMODE_ASPECT_16_9, 0
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* We have a special version of fb_mode_is_equal that ignores
|
||||
* pixclock, since for many CEA modes, 2 frequencies are supported
|
||||
* e.g. 640x480 @ 60Hz or 59.94Hz
|
||||
*/
|
||||
int mxc_edid_fb_mode_is_equal(bool use_aspect,
|
||||
const struct fb_videomode *mode1,
|
||||
const struct fb_videomode *mode2)
|
||||
{
|
||||
u32 mask;
|
||||
|
||||
if (use_aspect)
|
||||
mask = ~0;
|
||||
else
|
||||
mask = ~FB_VMODE_ASPECT_MASK;
|
||||
|
||||
return (mode1->xres == mode2->xres &&
|
||||
mode1->yres == mode2->yres &&
|
||||
mode1->hsync_len == mode2->hsync_len &&
|
||||
mode1->vsync_len == mode2->vsync_len &&
|
||||
mode1->left_margin == mode2->left_margin &&
|
||||
mode1->right_margin == mode2->right_margin &&
|
||||
mode1->upper_margin == mode2->upper_margin &&
|
||||
mode1->lower_margin == mode2->lower_margin &&
|
||||
mode1->sync == mode2->sync &&
|
||||
/* refresh check, 59.94Hz and 60Hz have the same parameter
|
||||
* in struct of mxc_cea_mode */
|
||||
abs(mode1->refresh - mode2->refresh) <= 1 &&
|
||||
(mode1->vmode & mask) == (mode2->vmode & mask));
|
||||
}
|
||||
|
||||
static void get_detailed_timing(unsigned char *block,
|
||||
struct fb_videomode *mode)
|
||||
{
|
||||
mode->xres = H_ACTIVE;
|
||||
mode->yres = V_ACTIVE;
|
||||
mode->pixclock = PIXEL_CLOCK;
|
||||
mode->pixclock /= 1000;
|
||||
mode->pixclock = KHZ2PICOS(mode->pixclock);
|
||||
mode->right_margin = H_SYNC_OFFSET;
|
||||
mode->left_margin = (H_ACTIVE + H_BLANKING) -
|
||||
(H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
|
||||
mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
|
||||
V_SYNC_WIDTH;
|
||||
mode->lower_margin = V_SYNC_OFFSET;
|
||||
mode->hsync_len = H_SYNC_WIDTH;
|
||||
mode->vsync_len = V_SYNC_WIDTH;
|
||||
if (HSYNC_POSITIVE)
|
||||
mode->sync |= FB_SYNC_HOR_HIGH_ACT;
|
||||
if (VSYNC_POSITIVE)
|
||||
mode->sync |= FB_SYNC_VERT_HIGH_ACT;
|
||||
mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
|
||||
(V_ACTIVE + V_BLANKING));
|
||||
if (INTERLACED) {
|
||||
mode->yres *= 2;
|
||||
mode->upper_margin *= 2;
|
||||
mode->lower_margin *= 2;
|
||||
mode->vsync_len *= 2;
|
||||
mode->vmode |= FB_VMODE_INTERLACED;
|
||||
}
|
||||
mode->flag = FB_MODE_IS_DETAILED;
|
||||
|
||||
if ((H_SIZE / 16) == (V_SIZE / 9))
|
||||
mode->vmode |= FB_VMODE_ASPECT_16_9;
|
||||
else if ((H_SIZE / 4) == (V_SIZE / 3))
|
||||
mode->vmode |= FB_VMODE_ASPECT_4_3;
|
||||
else if ((mode->xres / 16) == (mode->yres / 9))
|
||||
mode->vmode |= FB_VMODE_ASPECT_16_9;
|
||||
else if ((mode->xres / 4) == (mode->yres / 3))
|
||||
mode->vmode |= FB_VMODE_ASPECT_4_3;
|
||||
|
||||
if (mode->vmode & FB_VMODE_ASPECT_16_9)
|
||||
DPRINTK("Aspect ratio: 16:9\n");
|
||||
if (mode->vmode & FB_VMODE_ASPECT_4_3)
|
||||
DPRINTK("Aspect ratio: 4:3\n");
|
||||
DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000);
|
||||
DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
|
||||
H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
|
||||
DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
|
||||
V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
|
||||
DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
|
||||
(VSYNC_POSITIVE) ? "+" : "-");
|
||||
}
|
||||
|
||||
int mxc_edid_parse_ext_blk(unsigned char *edid,
|
||||
struct mxc_edid_cfg *cfg,
|
||||
struct fb_monspecs *specs)
|
||||
{
|
||||
char detail_timing_desc_offset;
|
||||
struct fb_videomode *mode, *m;
|
||||
unsigned char index = 0x0;
|
||||
unsigned char *block;
|
||||
int i, num = 0, revision;
|
||||
|
||||
if (edid[index++] != 0x2) /* only support cea ext block now */
|
||||
return 0;
|
||||
revision = edid[index++];
|
||||
DPRINTK("cea extent revision %d\n", revision);
|
||||
mode = kzalloc(50 * sizeof(struct fb_videomode), GFP_KERNEL);
|
||||
if (mode == NULL)
|
||||
return -1;
|
||||
|
||||
detail_timing_desc_offset = edid[index++];
|
||||
|
||||
if (revision >= 2) {
|
||||
cfg->cea_underscan = (edid[index] >> 7) & 0x1;
|
||||
cfg->cea_basicaudio = (edid[index] >> 6) & 0x1;
|
||||
cfg->cea_ycbcr444 = (edid[index] >> 5) & 0x1;
|
||||
cfg->cea_ycbcr422 = (edid[index] >> 4) & 0x1;
|
||||
|
||||
DPRINTK("CEA underscan %d\n", cfg->cea_underscan);
|
||||
DPRINTK("CEA basicaudio %d\n", cfg->cea_basicaudio);
|
||||
DPRINTK("CEA ycbcr444 %d\n", cfg->cea_ycbcr444);
|
||||
DPRINTK("CEA ycbcr422 %d\n", cfg->cea_ycbcr422);
|
||||
}
|
||||
|
||||
if (revision >= 3) {
|
||||
/* short desc */
|
||||
DPRINTK("CEA Short desc timmings\n");
|
||||
index++;
|
||||
while (index < detail_timing_desc_offset) {
|
||||
unsigned char tagcode, blklen;
|
||||
|
||||
tagcode = (edid[index] >> 5) & 0x7;
|
||||
blklen = (edid[index]) & 0x1f;
|
||||
|
||||
DPRINTK("Tagcode %x Len %d\n", tagcode, blklen);
|
||||
|
||||
switch (tagcode) {
|
||||
case 0x2: /*Video data block*/
|
||||
{
|
||||
int cea_idx;
|
||||
i = 0;
|
||||
while (i < blklen) {
|
||||
index++;
|
||||
cea_idx = edid[index] & 0x7f;
|
||||
if (cea_idx < ARRAY_SIZE(mxc_cea_mode) &&
|
||||
(mxc_cea_mode[cea_idx].xres)) {
|
||||
DPRINTK("Support CEA Format #%d\n", cea_idx);
|
||||
mode[num] = mxc_cea_mode[cea_idx];
|
||||
mode[num].flag |= FB_MODE_IS_STANDARD;
|
||||
num++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x3: /*Vendor specific data*/
|
||||
{
|
||||
unsigned char IEEE_reg_iden[3];
|
||||
unsigned char deep_color;
|
||||
unsigned char latency_present;
|
||||
unsigned char I_latency_present;
|
||||
unsigned char hdmi_video_present;
|
||||
unsigned char hdmi_3d_present;
|
||||
unsigned char hdmi_3d_multi_present;
|
||||
unsigned char hdmi_vic_len;
|
||||
unsigned char hdmi_3d_len;
|
||||
unsigned char index_inc = 0;
|
||||
unsigned char vsd_end;
|
||||
|
||||
vsd_end = index + blklen;
|
||||
|
||||
IEEE_reg_iden[0] = edid[index+1];
|
||||
IEEE_reg_iden[1] = edid[index+2];
|
||||
IEEE_reg_iden[2] = edid[index+3];
|
||||
cfg->physical_address[0] = (edid[index+4] & 0xf0) >> 4;
|
||||
cfg->physical_address[1] = (edid[index+4] & 0x0f);
|
||||
cfg->physical_address[2] = (edid[index+5] & 0xf0) >> 4;
|
||||
cfg->physical_address[3] = (edid[index+5] & 0x0f);
|
||||
|
||||
if ((IEEE_reg_iden[0] == 0x03) &&
|
||||
(IEEE_reg_iden[1] == 0x0c) &&
|
||||
(IEEE_reg_iden[2] == 0x00))
|
||||
cfg->hdmi_cap = 1;
|
||||
|
||||
if (blklen > 5) {
|
||||
deep_color = edid[index+6];
|
||||
if (deep_color & 0x80)
|
||||
cfg->vsd_support_ai = true;
|
||||
if (deep_color & 0x40)
|
||||
cfg->vsd_dc_48bit = true;
|
||||
if (deep_color & 0x20)
|
||||
cfg->vsd_dc_36bit = true;
|
||||
if (deep_color & 0x10)
|
||||
cfg->vsd_dc_30bit = true;
|
||||
if (deep_color & 0x08)
|
||||
cfg->vsd_dc_y444 = true;
|
||||
if (deep_color & 0x01)
|
||||
cfg->vsd_dvi_dual = true;
|
||||
}
|
||||
|
||||
DPRINTK("VSD hdmi capability %d\n", cfg->hdmi_cap);
|
||||
DPRINTK("VSD support ai %d\n", cfg->vsd_support_ai);
|
||||
DPRINTK("VSD support deep color 48bit %d\n", cfg->vsd_dc_48bit);
|
||||
DPRINTK("VSD support deep color 36bit %d\n", cfg->vsd_dc_36bit);
|
||||
DPRINTK("VSD support deep color 30bit %d\n", cfg->vsd_dc_30bit);
|
||||
DPRINTK("VSD support deep color y444 %d\n", cfg->vsd_dc_y444);
|
||||
DPRINTK("VSD support dvi dual %d\n", cfg->vsd_dvi_dual);
|
||||
|
||||
if (blklen > 6)
|
||||
cfg->vsd_max_tmdsclk_rate = edid[index+7] * 5;
|
||||
DPRINTK("VSD MAX TMDS CLOCK RATE %d\n", cfg->vsd_max_tmdsclk_rate);
|
||||
|
||||
if (blklen > 7) {
|
||||
latency_present = edid[index+8] >> 7;
|
||||
I_latency_present = (edid[index+8] & 0x40) >> 6;
|
||||
hdmi_video_present = (edid[index+8] & 0x20) >> 5;
|
||||
cfg->vsd_cnc3 = (edid[index+8] & 0x8) >> 3;
|
||||
cfg->vsd_cnc2 = (edid[index+8] & 0x4) >> 2;
|
||||
cfg->vsd_cnc1 = (edid[index+8] & 0x2) >> 1;
|
||||
cfg->vsd_cnc0 = edid[index+8] & 0x1;
|
||||
|
||||
DPRINTK("VSD cnc0 %d\n", cfg->vsd_cnc0);
|
||||
DPRINTK("VSD cnc1 %d\n", cfg->vsd_cnc1);
|
||||
DPRINTK("VSD cnc2 %d\n", cfg->vsd_cnc2);
|
||||
DPRINTK("VSD cnc3 %d\n", cfg->vsd_cnc3);
|
||||
DPRINTK("latency_present %d\n", latency_present);
|
||||
DPRINTK("I_latency_present %d\n", I_latency_present);
|
||||
DPRINTK("hdmi_video_present %d\n", hdmi_video_present);
|
||||
|
||||
} else {
|
||||
index += blklen;
|
||||
break;
|
||||
}
|
||||
|
||||
index += 9;
|
||||
|
||||
/*latency present */
|
||||
if (latency_present) {
|
||||
cfg->vsd_video_latency = edid[index++];
|
||||
cfg->vsd_audio_latency = edid[index++];
|
||||
|
||||
if (I_latency_present) {
|
||||
cfg->vsd_I_video_latency = edid[index++];
|
||||
cfg->vsd_I_audio_latency = edid[index++];
|
||||
} else {
|
||||
cfg->vsd_I_video_latency = cfg->vsd_video_latency;
|
||||
cfg->vsd_I_audio_latency = cfg->vsd_audio_latency;
|
||||
}
|
||||
|
||||
DPRINTK("VSD latency video_latency %d\n", cfg->vsd_video_latency);
|
||||
DPRINTK("VSD latency audio_latency %d\n", cfg->vsd_audio_latency);
|
||||
DPRINTK("VSD latency I_video_latency %d\n", cfg->vsd_I_video_latency);
|
||||
DPRINTK("VSD latency I_audio_latency %d\n", cfg->vsd_I_audio_latency);
|
||||
}
|
||||
|
||||
if (hdmi_video_present) {
|
||||
hdmi_3d_present = edid[index] >> 7;
|
||||
hdmi_3d_multi_present = (edid[index] & 0x60) >> 5;
|
||||
index++;
|
||||
hdmi_vic_len = (edid[index] & 0xe0) >> 5;
|
||||
hdmi_3d_len = edid[index] & 0x1f;
|
||||
index++;
|
||||
|
||||
DPRINTK("hdmi_3d_present %d\n", hdmi_3d_present);
|
||||
DPRINTK("hdmi_3d_multi_present %d\n", hdmi_3d_multi_present);
|
||||
DPRINTK("hdmi_vic_len %d\n", hdmi_vic_len);
|
||||
DPRINTK("hdmi_3d_len %d\n", hdmi_3d_len);
|
||||
|
||||
if (hdmi_vic_len > 0) {
|
||||
for (i = 0; i < hdmi_vic_len; i++) {
|
||||
cfg->hdmi_vic[i] = edid[index++];
|
||||
DPRINTK("HDMI_vic=%d\n", cfg->hdmi_vic[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (hdmi_3d_len > 0) {
|
||||
if (hdmi_3d_present) {
|
||||
if (hdmi_3d_multi_present == 0x1) {
|
||||
cfg->hdmi_3d_struct_all = (edid[index] << 8) | edid[index+1];
|
||||
index_inc = 2;
|
||||
} else if (hdmi_3d_multi_present == 0x2) {
|
||||
cfg->hdmi_3d_struct_all = (edid[index] << 8) | edid[index+1];
|
||||
cfg->hdmi_3d_mask_all = (edid[index+2] << 8) | edid[index+3];
|
||||
index_inc = 4;
|
||||
} else
|
||||
index_inc = 0;
|
||||
}
|
||||
|
||||
DPRINTK("HDMI 3d struct all =0x%x\n", cfg->hdmi_3d_struct_all);
|
||||
DPRINTK("HDMI 3d mask all =0x%x\n", cfg->hdmi_3d_mask_all);
|
||||
|
||||
/* Read 2D vic 3D_struct */
|
||||
if ((hdmi_3d_len - index_inc) > 0) {
|
||||
DPRINTK("Support 3D video format\n");
|
||||
i = 0;
|
||||
while ((hdmi_3d_len - index_inc) > 0) {
|
||||
|
||||
cfg->hdmi_3d_format[i].vic_order_2d = edid[index+index_inc] >> 4;
|
||||
cfg->hdmi_3d_format[i].struct_3d = edid[index+index_inc] & 0x0f;
|
||||
index_inc++;
|
||||
|
||||
if (cfg->hdmi_3d_format[i].struct_3d == 8) {
|
||||
cfg->hdmi_3d_format[i].detail_3d = edid[index+index_inc] >> 4;
|
||||
index_inc++;
|
||||
} else if (cfg->hdmi_3d_format[i].struct_3d > 8) {
|
||||
cfg->hdmi_3d_format[i].detail_3d = 0;
|
||||
index_inc++;
|
||||
}
|
||||
|
||||
DPRINTK("vic_order_2d=%d, 3d_struct=%d, 3d_detail=0x%x\n",
|
||||
cfg->hdmi_3d_format[i].vic_order_2d,
|
||||
cfg->hdmi_3d_format[i].struct_3d,
|
||||
cfg->hdmi_3d_format[i].detail_3d);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
index += index_inc;
|
||||
}
|
||||
}
|
||||
|
||||
index = vsd_end;
|
||||
|
||||
break;
|
||||
}
|
||||
case 0x1: /*Audio data block*/
|
||||
{
|
||||
u8 audio_format, max_ch, byte1, byte2, byte3;
|
||||
|
||||
i = 0;
|
||||
cfg->max_channels = 0;
|
||||
cfg->sample_rates = 0;
|
||||
cfg->sample_sizes = 0;
|
||||
|
||||
while (i < blklen) {
|
||||
byte1 = edid[index + 1];
|
||||
byte2 = edid[index + 2];
|
||||
byte3 = edid[index + 3];
|
||||
index += 3;
|
||||
i += 3;
|
||||
|
||||
audio_format = byte1 >> 3;
|
||||
max_ch = (byte1 & 0x07) + 1;
|
||||
|
||||
DPRINTK("Audio Format Descriptor : %2d\n", audio_format);
|
||||
DPRINTK("Max Number of Channels : %2d\n", max_ch);
|
||||
DPRINTK("Sample Rates : %02x\n", byte2);
|
||||
|
||||
/* ALSA can't specify specific compressed
|
||||
* formats, so only care about PCM for now. */
|
||||
if (audio_format == AUDIO_CODING_TYPE_LPCM) {
|
||||
if (max_ch > cfg->max_channels)
|
||||
cfg->max_channels = max_ch;
|
||||
|
||||
cfg->sample_rates |= byte2;
|
||||
cfg->sample_sizes |= byte3 & 0x7;
|
||||
DPRINTK("Sample Sizes : %02x\n",
|
||||
byte3 & 0x7);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x4: /*Speaker allocation block*/
|
||||
{
|
||||
i = 0;
|
||||
while (i < blklen) {
|
||||
cfg->speaker_alloc = edid[index + 1];
|
||||
index += 3;
|
||||
i += 3;
|
||||
DPRINTK("Speaker Alloc : %02x\n", cfg->speaker_alloc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x7: /*User extended block*/
|
||||
default:
|
||||
/* skip */
|
||||
DPRINTK("Not handle block, tagcode = 0x%x\n", tagcode);
|
||||
index += blklen;
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
/* long desc */
|
||||
DPRINTK("CEA long desc timmings\n");
|
||||
index = detail_timing_desc_offset;
|
||||
block = edid + index;
|
||||
while (index < (EDID_LENGTH - DETAILED_TIMING_DESCRIPTION_SIZE)) {
|
||||
if (!(block[0] == 0x00 && block[1] == 0x00)) {
|
||||
get_detailed_timing(block, &mode[num]);
|
||||
num++;
|
||||
}
|
||||
block += DETAILED_TIMING_DESCRIPTION_SIZE;
|
||||
index += DETAILED_TIMING_DESCRIPTION_SIZE;
|
||||
}
|
||||
|
||||
if (!num) {
|
||||
kfree(mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
m = kmalloc((num + specs->modedb_len) *
|
||||
sizeof(struct fb_videomode), GFP_KERNEL);
|
||||
if (!m)
|
||||
return 0;
|
||||
|
||||
if (specs->modedb_len) {
|
||||
memmove(m, specs->modedb,
|
||||
specs->modedb_len * sizeof(struct fb_videomode));
|
||||
kfree(specs->modedb);
|
||||
}
|
||||
memmove(m+specs->modedb_len, mode,
|
||||
num * sizeof(struct fb_videomode));
|
||||
kfree(mode);
|
||||
|
||||
specs->modedb_len += num;
|
||||
specs->modedb = m;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mxc_edid_parse_ext_blk);
|
||||
|
||||
static int mxc_edid_readblk(struct i2c_adapter *adp,
|
||||
unsigned short addr, unsigned char *edid)
|
||||
{
|
||||
int ret = 0, extblknum = 0;
|
||||
unsigned char regaddr = 0x0;
|
||||
struct i2c_msg msg[2] = {
|
||||
{
|
||||
.addr = addr,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = ®addr,
|
||||
}, {
|
||||
.addr = addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = EDID_LENGTH,
|
||||
.buf = edid,
|
||||
},
|
||||
};
|
||||
|
||||
ret = i2c_transfer(adp, msg, ARRAY_SIZE(msg));
|
||||
if (ret != ARRAY_SIZE(msg)) {
|
||||
DPRINTK("unable to read EDID block\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (edid[1] == 0x00)
|
||||
return -ENOENT;
|
||||
|
||||
extblknum = edid[0x7E];
|
||||
|
||||
if (extblknum) {
|
||||
regaddr = 128;
|
||||
msg[1].buf = edid + EDID_LENGTH;
|
||||
|
||||
ret = i2c_transfer(adp, msg, ARRAY_SIZE(msg));
|
||||
if (ret != ARRAY_SIZE(msg)) {
|
||||
DPRINTK("unable to read EDID ext block\n");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return extblknum;
|
||||
}
|
||||
|
||||
static int mxc_edid_readsegblk(struct i2c_adapter *adp, unsigned short addr,
|
||||
unsigned char *edid, int seg_num)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned char segment = 0x1, regaddr = 0;
|
||||
struct i2c_msg msg[3] = {
|
||||
{
|
||||
.addr = 0x30,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = &segment,
|
||||
}, {
|
||||
.addr = addr,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = ®addr,
|
||||
}, {
|
||||
.addr = addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = EDID_LENGTH,
|
||||
.buf = edid,
|
||||
},
|
||||
};
|
||||
|
||||
ret = i2c_transfer(adp, msg, ARRAY_SIZE(msg));
|
||||
if (ret != ARRAY_SIZE(msg)) {
|
||||
DPRINTK("unable to read EDID block\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (seg_num == 2) {
|
||||
regaddr = 128;
|
||||
msg[2].buf = edid + EDID_LENGTH;
|
||||
|
||||
ret = i2c_transfer(adp, msg, ARRAY_SIZE(msg));
|
||||
if (ret != ARRAY_SIZE(msg)) {
|
||||
DPRINTK("unable to read EDID block\n");
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mxc_edid_var_to_vic(struct fb_var_screeninfo *var)
|
||||
{
|
||||
int i;
|
||||
struct fb_videomode m;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mxc_cea_mode); i++) {
|
||||
fb_var_to_videomode(&m, var);
|
||||
if (mxc_edid_fb_mode_is_equal(false, &m, &mxc_cea_mode[i]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(mxc_cea_mode))
|
||||
return 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
EXPORT_SYMBOL(mxc_edid_var_to_vic);
|
||||
|
||||
int mxc_edid_mode_to_vic(const struct fb_videomode *mode)
|
||||
{
|
||||
int i;
|
||||
bool use_aspect = (mode->vmode & FB_VMODE_ASPECT_MASK);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(mxc_cea_mode); i++) {
|
||||
if (mxc_edid_fb_mode_is_equal(use_aspect, mode, &mxc_cea_mode[i]))
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(mxc_cea_mode))
|
||||
return 0;
|
||||
|
||||
return i;
|
||||
}
|
||||
EXPORT_SYMBOL(mxc_edid_mode_to_vic);
|
||||
|
||||
/* make sure edid has 512 bytes*/
|
||||
int mxc_edid_read(struct i2c_adapter *adp, unsigned short addr,
|
||||
unsigned char *edid, struct mxc_edid_cfg *cfg, struct fb_info *fbi)
|
||||
{
|
||||
int ret = 0, extblknum;
|
||||
if (!adp || !edid || !cfg || !fbi)
|
||||
return -EINVAL;
|
||||
|
||||
memset(edid, 0, EDID_LENGTH*4);
|
||||
memset(cfg, 0, sizeof(struct mxc_edid_cfg));
|
||||
|
||||
extblknum = mxc_edid_readblk(adp, addr, edid);
|
||||
if (extblknum < 0)
|
||||
return extblknum;
|
||||
|
||||
/* edid first block parsing */
|
||||
memset(&fbi->monspecs, 0, sizeof(fbi->monspecs));
|
||||
fb_edid_to_monspecs(edid, &fbi->monspecs);
|
||||
|
||||
if (extblknum) {
|
||||
int i;
|
||||
|
||||
/* FIXME: mxc_edid_readsegblk() won't read more than 2 blocks
|
||||
* and the for-loop will read past the end of the buffer! :-( */
|
||||
if (extblknum > 3) {
|
||||
WARN_ON(true);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* need read segment block? */
|
||||
if (extblknum > 1) {
|
||||
ret = mxc_edid_readsegblk(adp, addr,
|
||||
edid + EDID_LENGTH*2, extblknum - 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 1; i <= extblknum; i++)
|
||||
/* edid ext block parsing */
|
||||
mxc_edid_parse_ext_blk(edid + i*EDID_LENGTH,
|
||||
cfg, &fbi->monspecs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mxc_edid_read);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/ipu.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mxcfb.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "mxc_dispdrv.h"
|
||||
|
||||
struct mxc_lcd_platform_data {
|
||||
u32 default_ifmt;
|
||||
u32 ipu_id;
|
||||
u32 disp_id;
|
||||
};
|
||||
|
||||
struct mxc_lcdif_data {
|
||||
struct platform_device *pdev;
|
||||
struct mxc_dispdrv_handle *disp_lcdif;
|
||||
};
|
||||
|
||||
#define DISPDRV_LCD "lcd"
|
||||
|
||||
static struct fb_videomode lcdif_modedb[] = {
|
||||
{
|
||||
/* 800x480 @ 57 Hz , pixel clk @ 27MHz */
|
||||
"CLAA-WVGA", 57, 800, 480, 37037, 40, 60, 10, 10, 20, 10,
|
||||
FB_SYNC_CLK_LAT_FALL,
|
||||
FB_VMODE_NONINTERLACED,
|
||||
0,},
|
||||
{
|
||||
/* 800x480 @ 60 Hz , pixel clk @ 32MHz */
|
||||
"SEIKO-WVGA", 60, 800, 480, 29850, 89, 164, 23, 10, 10, 10,
|
||||
FB_SYNC_CLK_LAT_FALL,
|
||||
FB_VMODE_NONINTERLACED,
|
||||
0,},
|
||||
};
|
||||
static int lcdif_modedb_sz = ARRAY_SIZE(lcdif_modedb);
|
||||
|
||||
static int lcdif_init(struct mxc_dispdrv_handle *disp,
|
||||
struct mxc_dispdrv_setting *setting)
|
||||
{
|
||||
int ret, i;
|
||||
struct mxc_lcdif_data *lcdif = mxc_dispdrv_getdata(disp);
|
||||
struct device *dev = &lcdif->pdev->dev;
|
||||
struct mxc_lcd_platform_data *plat_data = dev->platform_data;
|
||||
struct fb_videomode *modedb = lcdif_modedb;
|
||||
int modedb_sz = lcdif_modedb_sz;
|
||||
|
||||
/* use platform defined ipu/di */
|
||||
ret = ipu_di_to_crtc(dev, plat_data->ipu_id,
|
||||
plat_data->disp_id, &setting->crtc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str,
|
||||
modedb, modedb_sz, NULL, setting->default_bpp);
|
||||
if (!ret) {
|
||||
fb_videomode_to_var(&setting->fbi->var, &modedb[0]);
|
||||
setting->if_fmt = plat_data->default_ifmt;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&setting->fbi->modelist);
|
||||
for (i = 0; i < modedb_sz; i++) {
|
||||
struct fb_videomode m;
|
||||
fb_var_to_videomode(&m, &setting->fbi->var);
|
||||
if (fb_mode_is_equal(&m, &modedb[i])) {
|
||||
fb_add_videomode(&modedb[i],
|
||||
&setting->fbi->modelist);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void lcdif_deinit(struct mxc_dispdrv_handle *disp)
|
||||
{
|
||||
/*TODO*/
|
||||
}
|
||||
|
||||
static struct mxc_dispdrv_driver lcdif_drv = {
|
||||
.name = DISPDRV_LCD,
|
||||
.init = lcdif_init,
|
||||
.deinit = lcdif_deinit,
|
||||
};
|
||||
|
||||
static int lcd_get_of_property(struct platform_device *pdev,
|
||||
struct mxc_lcd_platform_data *plat_data)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
int err;
|
||||
u32 ipu_id, disp_id;
|
||||
const char *default_ifmt;
|
||||
|
||||
err = of_property_read_string(np, "default_ifmt", &default_ifmt);
|
||||
if (err) {
|
||||
dev_dbg(&pdev->dev, "get of property default_ifmt fail\n");
|
||||
return err;
|
||||
}
|
||||
err = of_property_read_u32(np, "ipu_id", &ipu_id);
|
||||
if (err) {
|
||||
dev_dbg(&pdev->dev, "get of property ipu_id fail\n");
|
||||
return err;
|
||||
}
|
||||
err = of_property_read_u32(np, "disp_id", &disp_id);
|
||||
if (err) {
|
||||
dev_dbg(&pdev->dev, "get of property disp_id fail\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
plat_data->ipu_id = ipu_id;
|
||||
plat_data->disp_id = disp_id;
|
||||
if (!strncmp(default_ifmt, "RGB24", 5))
|
||||
plat_data->default_ifmt = IPU_PIX_FMT_RGB24;
|
||||
else if (!strncmp(default_ifmt, "BGR24", 5))
|
||||
plat_data->default_ifmt = IPU_PIX_FMT_BGR24;
|
||||
else if (!strncmp(default_ifmt, "GBR24", 5))
|
||||
plat_data->default_ifmt = IPU_PIX_FMT_GBR24;
|
||||
else if (!strncmp(default_ifmt, "RGB565", 6))
|
||||
plat_data->default_ifmt = IPU_PIX_FMT_RGB565;
|
||||
else if (!strncmp(default_ifmt, "RGB666", 6))
|
||||
plat_data->default_ifmt = IPU_PIX_FMT_RGB666;
|
||||
else if (!strncmp(default_ifmt, "YUV444", 6))
|
||||
plat_data->default_ifmt = IPU_PIX_FMT_YUV444;
|
||||
else if (!strncmp(default_ifmt, "LVDS666", 7))
|
||||
plat_data->default_ifmt = IPU_PIX_FMT_LVDS666;
|
||||
else if (!strncmp(default_ifmt, "YUYV16", 6))
|
||||
plat_data->default_ifmt = IPU_PIX_FMT_YUYV;
|
||||
else if (!strncmp(default_ifmt, "UYVY16", 6))
|
||||
plat_data->default_ifmt = IPU_PIX_FMT_UYVY;
|
||||
else if (!strncmp(default_ifmt, "YVYU16", 6))
|
||||
plat_data->default_ifmt = IPU_PIX_FMT_YVYU;
|
||||
else if (!strncmp(default_ifmt, "VYUY16", 6))
|
||||
plat_data->default_ifmt = IPU_PIX_FMT_VYUY;
|
||||
else {
|
||||
dev_err(&pdev->dev, "err default_ifmt!\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mxc_lcdif_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct pinctrl *pinctrl;
|
||||
struct mxc_lcdif_data *lcdif;
|
||||
struct mxc_lcd_platform_data *plat_data;
|
||||
|
||||
dev_dbg(&pdev->dev, "%s enter\n", __func__);
|
||||
lcdif = devm_kzalloc(&pdev->dev, sizeof(struct mxc_lcdif_data),
|
||||
GFP_KERNEL);
|
||||
if (!lcdif)
|
||||
return -ENOMEM;
|
||||
plat_data = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct mxc_lcd_platform_data),
|
||||
GFP_KERNEL);
|
||||
if (!plat_data)
|
||||
return -ENOMEM;
|
||||
pdev->dev.platform_data = plat_data;
|
||||
|
||||
ret = lcd_get_of_property(pdev, plat_data);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "get lcd of property fail\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
|
||||
if (IS_ERR(pinctrl)) {
|
||||
dev_err(&pdev->dev, "can't get/select pinctrl\n");
|
||||
return PTR_ERR(pinctrl);
|
||||
}
|
||||
|
||||
lcdif->pdev = pdev;
|
||||
lcdif->disp_lcdif = mxc_dispdrv_register(&lcdif_drv);
|
||||
mxc_dispdrv_setdata(lcdif->disp_lcdif, lcdif);
|
||||
|
||||
dev_set_drvdata(&pdev->dev, lcdif);
|
||||
dev_dbg(&pdev->dev, "%s exit\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxc_lcdif_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mxc_lcdif_data *lcdif = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
mxc_dispdrv_puthandle(lcdif->disp_lcdif);
|
||||
mxc_dispdrv_unregister(lcdif->disp_lcdif);
|
||||
kfree(lcdif);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id imx_lcd_dt_ids[] = {
|
||||
{ .compatible = "fsl,lcd"},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
static struct platform_driver mxc_lcdif_driver = {
|
||||
.driver = {
|
||||
.name = "mxc_lcdif",
|
||||
.of_match_table = imx_lcd_dt_ids,
|
||||
},
|
||||
.probe = mxc_lcdif_probe,
|
||||
.remove = mxc_lcdif_remove,
|
||||
};
|
||||
|
||||
static int __init mxc_lcdif_init(void)
|
||||
{
|
||||
return platform_driver_register(&mxc_lcdif_driver);
|
||||
}
|
||||
|
||||
static void __exit mxc_lcdif_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mxc_lcdif_driver);
|
||||
}
|
||||
|
||||
module_init(mxc_lcdif_init);
|
||||
module_exit(mxc_lcdif_exit);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("i.MX ipuv3 LCD extern port driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
#ifndef __LINUX_IPU_V3_PRE_H_
|
||||
#define __LINUX_IPU_V3_PRE_H_
|
||||
|
||||
#define IPU_PRE_MAX_WIDTH 1920
|
||||
#define IPU_PRE_MAX_BPP 4
|
||||
|
||||
struct ipu_rect {
|
||||
int left;
|
||||
int top;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
struct ipu_pre_context {
|
||||
bool repeat;
|
||||
bool vflip;
|
||||
bool handshake_en;
|
||||
bool hsk_abort_en;
|
||||
unsigned int hsk_line_num;
|
||||
bool sdw_update;
|
||||
unsigned int block_size;
|
||||
unsigned int interlaced;
|
||||
unsigned int prefetch_mode;
|
||||
|
||||
unsigned long cur_buf;
|
||||
unsigned long next_buf;
|
||||
|
||||
unsigned int tile_fmt;
|
||||
|
||||
unsigned int read_burst;
|
||||
unsigned int prefetch_input_bpp;
|
||||
unsigned int prefetch_input_pixel_fmt;
|
||||
unsigned int prefetch_shift_offset;
|
||||
unsigned int prefetch_shift_width;
|
||||
bool shift_bypass;
|
||||
bool field_inverse;
|
||||
bool tpr_coor_offset_en;
|
||||
/* the output of prefetch is
|
||||
* also the input of store
|
||||
*/
|
||||
struct ipu_rect prefetch_output_size;
|
||||
unsigned int prefetch_input_active_width;
|
||||
unsigned int prefetch_input_width;
|
||||
unsigned int prefetch_input_height;
|
||||
unsigned int store_pitch;
|
||||
int interlace_offset;
|
||||
|
||||
bool store_en;
|
||||
unsigned int write_burst;
|
||||
unsigned int store_output_bpp;
|
||||
|
||||
unsigned int sec_buf_off;
|
||||
unsigned int trd_buf_off;
|
||||
|
||||
/* return for IPU fb caller */
|
||||
unsigned long store_addr;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MXC_IPU_V3_PRE
|
||||
int ipu_pre_alloc(int ipu_id, ipu_channel_t ipu_ch);
|
||||
void ipu_pre_free(unsigned int *id);
|
||||
unsigned long ipu_pre_alloc_double_buffer(unsigned int id, unsigned int size);
|
||||
void ipu_pre_free_double_buffer(unsigned int id);
|
||||
int ipu_pre_config(int id, struct ipu_pre_context *config);
|
||||
int ipu_pre_enable(int id);
|
||||
void ipu_pre_disable(int id);
|
||||
int ipu_pre_set_fb_buffer(int id, unsigned long fb_paddr,
|
||||
unsigned int x_crop,
|
||||
unsigned int y_crop,
|
||||
unsigned int sec_buf_off,
|
||||
unsigned int trd_buf_off);
|
||||
int ipu_pre_sdw_update(int id);
|
||||
#else
|
||||
int ipu_pre_alloc(int ipu_id, ipu_channel_t channel)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
void ipu_pre_free(unsigned int *id)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned long ipu_pre_alloc_double_buffer(unsigned int id, unsigned int size)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
void ipu_pre_free_double_buffer(unsigned int id)
|
||||
{
|
||||
}
|
||||
|
||||
int ipu_pre_config(int id, struct ipu_pre_context *config)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int ipu_pre_enable(int id)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
void ipu_pre_disable(int id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int ipu_pre_set_fb_buffer(int id, unsigned long fb_paddr,
|
||||
unsigned int x_crop,
|
||||
unsigned int y_crop,
|
||||
unsigned int sec_buf_off,
|
||||
unsigned int trd_buf_off)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
int ipu_pre_sdw_update(int id)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
#endif /* __LINUX_IPU_V3_PRE_H_ */
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
#ifndef __LINUX_IPU_V3_PRG_H_
|
||||
#define __LINUX_IPU_V3_PRG_H_
|
||||
|
||||
#include <linux/ipu-v3.h>
|
||||
|
||||
#define PRG_SO_INTERLACE 1
|
||||
#define PRG_SO_PROGRESSIVE 0
|
||||
#define PRG_BLOCK_MODE 1
|
||||
#define PRG_SCAN_MODE 0
|
||||
|
||||
struct ipu_prg_config {
|
||||
unsigned int id;
|
||||
unsigned int pre_num;
|
||||
ipu_channel_t ipu_ch;
|
||||
unsigned int stride;
|
||||
unsigned int height;
|
||||
unsigned int ipu_height;
|
||||
unsigned int crop_line;
|
||||
unsigned int so;
|
||||
unsigned int ilo;
|
||||
unsigned int block_mode;
|
||||
bool vflip;
|
||||
u32 baddr;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MXC_IPU_V3_PRG
|
||||
int ipu_prg_config(struct ipu_prg_config *config);
|
||||
int ipu_prg_disable(unsigned int ipu_id, unsigned int pre_num);
|
||||
int ipu_prg_wait_buf_ready(unsigned int ipu_id, unsigned int pre_num,
|
||||
unsigned int hsk_line_num,
|
||||
int pre_store_out_height);
|
||||
#else
|
||||
int ipu_prg_config(struct ipu_prg_config *config)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int ipu_prg_disable(unsigned int ipu_id, unsigned int pre_num)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int ipu_prg_wait_buf_ready(unsigned int ipu_id, unsigned int pre_num,
|
||||
unsigned int hsk_line_num,
|
||||
int pre_store_out_height)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
#endif /* __LINUX_IPU_V3_PRG_H_ */
|
|
@ -0,0 +1,770 @@
|
|||
/*
|
||||
* Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
|
||||
* Copyright (C) 2011-2015 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_IPU_V3_H_
|
||||
#define __LINUX_IPU_V3_H_
|
||||
|
||||
#include <linux/ipu.h>
|
||||
|
||||
/* IPU Driver channels definitions. */
|
||||
/* Note these are different from IDMA channels */
|
||||
#define IPU_MAX_CH 32
|
||||
#define _MAKE_CHAN(num, v_in, g_in, a_in, out) \
|
||||
((num << 24) | (v_in << 18) | (g_in << 12) | (a_in << 6) | out)
|
||||
#define _MAKE_ALT_CHAN(ch) (ch | (IPU_MAX_CH << 24))
|
||||
#define IPU_CHAN_ID(ch) (ch >> 24)
|
||||
#define IPU_CHAN_ALT(ch) (ch & 0x02000000)
|
||||
#define IPU_CHAN_ALPHA_IN_DMA(ch) ((uint32_t) (ch >> 6) & 0x3F)
|
||||
#define IPU_CHAN_GRAPH_IN_DMA(ch) ((uint32_t) (ch >> 12) & 0x3F)
|
||||
#define IPU_CHAN_VIDEO_IN_DMA(ch) ((uint32_t) (ch >> 18) & 0x3F)
|
||||
#define IPU_CHAN_OUT_DMA(ch) ((uint32_t) (ch & 0x3F))
|
||||
#define NO_DMA 0x3F
|
||||
#define ALT 1
|
||||
/*!
|
||||
* Enumeration of IPU logical channels. An IPU logical channel is defined as a
|
||||
* combination of an input (memory to IPU), output (IPU to memory), and/or
|
||||
* secondary input IDMA channels and in some cases an Image Converter task.
|
||||
* Some channels consist of only an input or output.
|
||||
*/
|
||||
typedef enum {
|
||||
CHAN_NONE = -1,
|
||||
MEM_ROT_ENC_MEM = _MAKE_CHAN(1, 45, NO_DMA, NO_DMA, 48),
|
||||
MEM_ROT_VF_MEM = _MAKE_CHAN(2, 46, NO_DMA, NO_DMA, 49),
|
||||
MEM_ROT_PP_MEM = _MAKE_CHAN(3, 47, NO_DMA, NO_DMA, 50),
|
||||
|
||||
MEM_PRP_ENC_MEM = _MAKE_CHAN(4, 12, 14, 17, 20),
|
||||
MEM_PRP_VF_MEM = _MAKE_CHAN(5, 12, 14, 17, 21),
|
||||
MEM_PP_MEM = _MAKE_CHAN(6, 11, 15, 18, 22),
|
||||
|
||||
MEM_DC_SYNC = _MAKE_CHAN(7, 28, NO_DMA, NO_DMA, NO_DMA),
|
||||
MEM_DC_ASYNC = _MAKE_CHAN(8, 41, NO_DMA, NO_DMA, NO_DMA),
|
||||
MEM_BG_SYNC = _MAKE_CHAN(9, 23, NO_DMA, 51, NO_DMA),
|
||||
MEM_FG_SYNC = _MAKE_CHAN(10, 27, NO_DMA, 31, NO_DMA),
|
||||
|
||||
MEM_BG_ASYNC0 = _MAKE_CHAN(11, 24, NO_DMA, 52, NO_DMA),
|
||||
MEM_FG_ASYNC0 = _MAKE_CHAN(12, 29, NO_DMA, 33, NO_DMA),
|
||||
MEM_BG_ASYNC1 = _MAKE_ALT_CHAN(MEM_BG_ASYNC0),
|
||||
MEM_FG_ASYNC1 = _MAKE_ALT_CHAN(MEM_FG_ASYNC0),
|
||||
|
||||
DIRECT_ASYNC0 = _MAKE_CHAN(13, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
|
||||
DIRECT_ASYNC1 = _MAKE_CHAN(14, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
|
||||
|
||||
CSI_MEM0 = _MAKE_CHAN(15, NO_DMA, NO_DMA, NO_DMA, 0),
|
||||
CSI_MEM1 = _MAKE_CHAN(16, NO_DMA, NO_DMA, NO_DMA, 1),
|
||||
CSI_MEM2 = _MAKE_CHAN(17, NO_DMA, NO_DMA, NO_DMA, 2),
|
||||
CSI_MEM3 = _MAKE_CHAN(18, NO_DMA, NO_DMA, NO_DMA, 3),
|
||||
|
||||
CSI_MEM = CSI_MEM0,
|
||||
|
||||
CSI_PRP_ENC_MEM = _MAKE_CHAN(19, NO_DMA, NO_DMA, NO_DMA, 20),
|
||||
CSI_PRP_VF_MEM = _MAKE_CHAN(20, NO_DMA, NO_DMA, NO_DMA, 21),
|
||||
|
||||
/* for vdi mem->vdi->ic->mem , add graphics plane and alpha*/
|
||||
MEM_VDI_PRP_VF_MEM_P = _MAKE_CHAN(21, 8, 14, 17, 21),
|
||||
MEM_VDI_PRP_VF_MEM = _MAKE_CHAN(22, 9, 14, 17, 21),
|
||||
MEM_VDI_PRP_VF_MEM_N = _MAKE_CHAN(23, 10, 14, 17, 21),
|
||||
|
||||
/* for vdi mem->vdi->mem */
|
||||
MEM_VDI_MEM_P = _MAKE_CHAN(24, 8, NO_DMA, NO_DMA, 5),
|
||||
MEM_VDI_MEM = _MAKE_CHAN(25, 9, NO_DMA, NO_DMA, 5),
|
||||
MEM_VDI_MEM_N = _MAKE_CHAN(26, 10, NO_DMA, NO_DMA, 5),
|
||||
|
||||
/* fake channel for vdoa to link with IPU */
|
||||
MEM_VDOA_MEM = _MAKE_CHAN(27, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
|
||||
|
||||
MEM_PP_ADC = CHAN_NONE,
|
||||
ADC_SYS2 = CHAN_NONE,
|
||||
|
||||
} ipu_channel_t;
|
||||
|
||||
/*!
|
||||
* Enumeration of types of buffers for a logical channel.
|
||||
*/
|
||||
typedef enum {
|
||||
IPU_OUTPUT_BUFFER = 0, /*!< Buffer for output from IPU */
|
||||
IPU_ALPHA_IN_BUFFER = 1, /*!< Buffer for input to IPU */
|
||||
IPU_GRAPH_IN_BUFFER = 2, /*!< Buffer for input to IPU */
|
||||
IPU_VIDEO_IN_BUFFER = 3, /*!< Buffer for input to IPU */
|
||||
IPU_INPUT_BUFFER = IPU_VIDEO_IN_BUFFER,
|
||||
IPU_SEC_INPUT_BUFFER = IPU_GRAPH_IN_BUFFER,
|
||||
} ipu_buffer_t;
|
||||
|
||||
#define IPU_PANEL_SERIAL 1
|
||||
#define IPU_PANEL_PARALLEL 2
|
||||
|
||||
/*!
|
||||
* Enumeration of ADC channel operation mode.
|
||||
*/
|
||||
typedef enum {
|
||||
Disable,
|
||||
WriteTemplateNonSeq,
|
||||
ReadTemplateNonSeq,
|
||||
WriteTemplateUnCon,
|
||||
ReadTemplateUnCon,
|
||||
WriteDataWithRS,
|
||||
WriteDataWoRS,
|
||||
WriteCmd
|
||||
} mcu_mode_t;
|
||||
|
||||
/*!
|
||||
* Enumeration of ADC channel addressing mode.
|
||||
*/
|
||||
typedef enum {
|
||||
FullWoBE,
|
||||
FullWithBE,
|
||||
XY
|
||||
} display_addressing_t;
|
||||
|
||||
/*!
|
||||
* Union of initialization parameters for a logical channel.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t csi;
|
||||
uint32_t mipi_id;
|
||||
uint32_t mipi_vc;
|
||||
bool mipi_en;
|
||||
bool interlaced;
|
||||
} csi_mem;
|
||||
struct {
|
||||
uint32_t in_width;
|
||||
uint32_t in_height;
|
||||
uint32_t in_pixel_fmt;
|
||||
uint32_t out_width;
|
||||
uint32_t out_height;
|
||||
uint32_t out_pixel_fmt;
|
||||
uint32_t outh_resize_ratio;
|
||||
uint32_t outv_resize_ratio;
|
||||
uint32_t csi;
|
||||
uint32_t mipi_id;
|
||||
uint32_t mipi_vc;
|
||||
bool mipi_en;
|
||||
} csi_prp_enc_mem;
|
||||
struct {
|
||||
uint32_t in_width;
|
||||
uint32_t in_height;
|
||||
uint32_t in_pixel_fmt;
|
||||
uint32_t out_width;
|
||||
uint32_t out_height;
|
||||
uint32_t out_pixel_fmt;
|
||||
uint32_t outh_resize_ratio;
|
||||
uint32_t outv_resize_ratio;
|
||||
} mem_prp_enc_mem;
|
||||
struct {
|
||||
uint32_t in_width;
|
||||
uint32_t in_height;
|
||||
uint32_t in_pixel_fmt;
|
||||
uint32_t out_width;
|
||||
uint32_t out_height;
|
||||
uint32_t out_pixel_fmt;
|
||||
} mem_rot_enc_mem;
|
||||
struct {
|
||||
uint32_t in_width;
|
||||
uint32_t in_height;
|
||||
uint32_t in_pixel_fmt;
|
||||
uint32_t out_width;
|
||||
uint32_t out_height;
|
||||
uint32_t out_pixel_fmt;
|
||||
uint32_t outh_resize_ratio;
|
||||
uint32_t outv_resize_ratio;
|
||||
bool graphics_combine_en;
|
||||
bool global_alpha_en;
|
||||
bool key_color_en;
|
||||
uint32_t in_g_pixel_fmt;
|
||||
uint8_t alpha;
|
||||
uint32_t key_color;
|
||||
bool alpha_chan_en;
|
||||
ipu_motion_sel motion_sel;
|
||||
enum v4l2_field field_fmt;
|
||||
uint32_t csi;
|
||||
uint32_t mipi_id;
|
||||
uint32_t mipi_vc;
|
||||
bool mipi_en;
|
||||
} csi_prp_vf_mem;
|
||||
struct {
|
||||
uint32_t in_width;
|
||||
uint32_t in_height;
|
||||
uint32_t in_pixel_fmt;
|
||||
uint32_t out_width;
|
||||
uint32_t out_height;
|
||||
uint32_t out_pixel_fmt;
|
||||
bool graphics_combine_en;
|
||||
bool global_alpha_en;
|
||||
bool key_color_en;
|
||||
display_port_t disp;
|
||||
uint32_t out_left;
|
||||
uint32_t out_top;
|
||||
} csi_prp_vf_adc;
|
||||
struct {
|
||||
uint32_t in_width;
|
||||
uint32_t in_height;
|
||||
uint32_t in_pixel_fmt;
|
||||
uint32_t out_width;
|
||||
uint32_t out_height;
|
||||
uint32_t out_pixel_fmt;
|
||||
uint32_t outh_resize_ratio;
|
||||
uint32_t outv_resize_ratio;
|
||||
bool graphics_combine_en;
|
||||
bool global_alpha_en;
|
||||
bool key_color_en;
|
||||
uint32_t in_g_pixel_fmt;
|
||||
uint8_t alpha;
|
||||
uint32_t key_color;
|
||||
bool alpha_chan_en;
|
||||
ipu_motion_sel motion_sel;
|
||||
enum v4l2_field field_fmt;
|
||||
} mem_prp_vf_mem;
|
||||
struct {
|
||||
uint32_t temp;
|
||||
} mem_prp_vf_adc;
|
||||
struct {
|
||||
uint32_t temp;
|
||||
} mem_rot_vf_mem;
|
||||
struct {
|
||||
uint32_t in_width;
|
||||
uint32_t in_height;
|
||||
uint32_t in_pixel_fmt;
|
||||
uint32_t out_width;
|
||||
uint32_t out_height;
|
||||
uint32_t out_pixel_fmt;
|
||||
uint32_t outh_resize_ratio;
|
||||
uint32_t outv_resize_ratio;
|
||||
bool graphics_combine_en;
|
||||
bool global_alpha_en;
|
||||
bool key_color_en;
|
||||
uint32_t in_g_pixel_fmt;
|
||||
uint8_t alpha;
|
||||
uint32_t key_color;
|
||||
bool alpha_chan_en;
|
||||
} mem_pp_mem;
|
||||
struct {
|
||||
uint32_t temp;
|
||||
} mem_rot_mem;
|
||||
struct {
|
||||
uint32_t in_width;
|
||||
uint32_t in_height;
|
||||
uint32_t in_pixel_fmt;
|
||||
uint32_t out_width;
|
||||
uint32_t out_height;
|
||||
uint32_t out_pixel_fmt;
|
||||
bool graphics_combine_en;
|
||||
bool global_alpha_en;
|
||||
bool key_color_en;
|
||||
display_port_t disp;
|
||||
uint32_t out_left;
|
||||
uint32_t out_top;
|
||||
} mem_pp_adc;
|
||||
struct {
|
||||
uint32_t di;
|
||||
bool interlaced;
|
||||
uint32_t in_pixel_fmt;
|
||||
uint32_t out_pixel_fmt;
|
||||
} mem_dc_sync;
|
||||
struct {
|
||||
uint32_t temp;
|
||||
} mem_sdc_fg;
|
||||
struct {
|
||||
uint32_t di;
|
||||
bool interlaced;
|
||||
uint32_t in_pixel_fmt;
|
||||
uint32_t out_pixel_fmt;
|
||||
bool alpha_chan_en;
|
||||
} mem_dp_bg_sync;
|
||||
struct {
|
||||
uint32_t temp;
|
||||
} mem_sdc_bg;
|
||||
struct {
|
||||
uint32_t di;
|
||||
bool interlaced;
|
||||
uint32_t in_pixel_fmt;
|
||||
uint32_t out_pixel_fmt;
|
||||
bool alpha_chan_en;
|
||||
} mem_dp_fg_sync;
|
||||
struct {
|
||||
uint32_t di;
|
||||
} direct_async;
|
||||
struct {
|
||||
display_port_t disp;
|
||||
mcu_mode_t ch_mode;
|
||||
uint32_t out_left;
|
||||
uint32_t out_top;
|
||||
} adc_sys1;
|
||||
struct {
|
||||
display_port_t disp;
|
||||
mcu_mode_t ch_mode;
|
||||
uint32_t out_left;
|
||||
uint32_t out_top;
|
||||
} adc_sys2;
|
||||
} ipu_channel_params_t;
|
||||
|
||||
/*
|
||||
* IPU_IRQF_ONESHOT - Interrupt is not reenabled after the irq handler finished.
|
||||
*/
|
||||
#define IPU_IRQF_NONE 0x00000000
|
||||
#define IPU_IRQF_ONESHOT 0x00000001
|
||||
|
||||
/*!
|
||||
* Enumeration of IPU interrupt sources.
|
||||
*/
|
||||
enum ipu_irq_line {
|
||||
IPU_IRQ_CSI0_OUT_EOF = 0,
|
||||
IPU_IRQ_CSI1_OUT_EOF = 1,
|
||||
IPU_IRQ_CSI2_OUT_EOF = 2,
|
||||
IPU_IRQ_CSI3_OUT_EOF = 3,
|
||||
IPU_IRQ_VDIC_OUT_EOF = 5,
|
||||
IPU_IRQ_VDI_P_IN_EOF = 8,
|
||||
IPU_IRQ_VDI_C_IN_EOF = 9,
|
||||
IPU_IRQ_VDI_N_IN_EOF = 10,
|
||||
IPU_IRQ_PP_IN_EOF = 11,
|
||||
IPU_IRQ_PRP_IN_EOF = 12,
|
||||
IPU_IRQ_PRP_GRAPH_IN_EOF = 14,
|
||||
IPU_IRQ_PP_GRAPH_IN_EOF = 15,
|
||||
IPU_IRQ_PRP_ALPHA_IN_EOF = 17,
|
||||
IPU_IRQ_PP_ALPHA_IN_EOF = 18,
|
||||
IPU_IRQ_PRP_ENC_OUT_EOF = 20,
|
||||
IPU_IRQ_PRP_VF_OUT_EOF = 21,
|
||||
IPU_IRQ_PP_OUT_EOF = 22,
|
||||
IPU_IRQ_BG_SYNC_EOF = 23,
|
||||
IPU_IRQ_BG_ASYNC_EOF = 24,
|
||||
IPU_IRQ_FG_SYNC_EOF = 27,
|
||||
IPU_IRQ_DC_SYNC_EOF = 28,
|
||||
IPU_IRQ_FG_ASYNC_EOF = 29,
|
||||
IPU_IRQ_FG_ALPHA_SYNC_EOF = 31,
|
||||
|
||||
IPU_IRQ_FG_ALPHA_ASYNC_EOF = 33,
|
||||
IPU_IRQ_DC_READ_EOF = 40,
|
||||
IPU_IRQ_DC_ASYNC_EOF = 41,
|
||||
IPU_IRQ_DC_CMD1_EOF = 42,
|
||||
IPU_IRQ_DC_CMD2_EOF = 43,
|
||||
IPU_IRQ_DC_MASK_EOF = 44,
|
||||
IPU_IRQ_PRP_ENC_ROT_IN_EOF = 45,
|
||||
IPU_IRQ_PRP_VF_ROT_IN_EOF = 46,
|
||||
IPU_IRQ_PP_ROT_IN_EOF = 47,
|
||||
IPU_IRQ_PRP_ENC_ROT_OUT_EOF = 48,
|
||||
IPU_IRQ_PRP_VF_ROT_OUT_EOF = 49,
|
||||
IPU_IRQ_PP_ROT_OUT_EOF = 50,
|
||||
IPU_IRQ_BG_ALPHA_SYNC_EOF = 51,
|
||||
IPU_IRQ_BG_ALPHA_ASYNC_EOF = 52,
|
||||
|
||||
IPU_IRQ_BG_SYNC_NFACK = 64 + 23,
|
||||
IPU_IRQ_FG_SYNC_NFACK = 64 + 27,
|
||||
IPU_IRQ_DC_SYNC_NFACK = 64 + 28,
|
||||
|
||||
IPU_IRQ_DP_SF_START = 448 + 2,
|
||||
IPU_IRQ_DP_SF_END = 448 + 3,
|
||||
IPU_IRQ_BG_SF_END = IPU_IRQ_DP_SF_END,
|
||||
IPU_IRQ_DC_FC_0 = 448 + 8,
|
||||
IPU_IRQ_DC_FC_1 = 448 + 9,
|
||||
IPU_IRQ_DC_FC_2 = 448 + 10,
|
||||
IPU_IRQ_DC_FC_3 = 448 + 11,
|
||||
IPU_IRQ_DC_FC_4 = 448 + 12,
|
||||
IPU_IRQ_DC_FC_6 = 448 + 13,
|
||||
IPU_IRQ_VSYNC_PRE_0 = 448 + 14,
|
||||
IPU_IRQ_VSYNC_PRE_1 = 448 + 15,
|
||||
|
||||
IPU_IRQ_COUNT
|
||||
};
|
||||
|
||||
/*!
|
||||
* Bitfield of Display Interface signal polarities.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned datamask_en:1;
|
||||
unsigned int_clk:1;
|
||||
unsigned interlaced:1;
|
||||
unsigned odd_field_first:1;
|
||||
unsigned clksel_en:1;
|
||||
unsigned clkidle_en:1;
|
||||
unsigned data_pol:1; /* true = inverted */
|
||||
unsigned clk_pol:1; /* true = rising edge */
|
||||
unsigned enable_pol:1;
|
||||
unsigned Hsync_pol:1; /* true = active high */
|
||||
unsigned Vsync_pol:1;
|
||||
} ipu_di_signal_cfg_t;
|
||||
|
||||
/*!
|
||||
* Bitfield of CSI signal polarities and modes.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
unsigned data_width:4;
|
||||
unsigned clk_mode:3;
|
||||
unsigned ext_vsync:1;
|
||||
unsigned Vsync_pol:1;
|
||||
unsigned Hsync_pol:1;
|
||||
unsigned pixclk_pol:1;
|
||||
unsigned data_pol:1;
|
||||
unsigned sens_clksrc:1;
|
||||
unsigned pack_tight:1;
|
||||
unsigned force_eof:1;
|
||||
unsigned data_en_pol:1;
|
||||
unsigned data_fmt;
|
||||
unsigned csi;
|
||||
unsigned mclk;
|
||||
} ipu_csi_signal_cfg_t;
|
||||
|
||||
/*!
|
||||
* Enumeration of CSI data bus widths.
|
||||
*/
|
||||
enum {
|
||||
IPU_CSI_DATA_WIDTH_4 = 0,
|
||||
IPU_CSI_DATA_WIDTH_8 = 1,
|
||||
IPU_CSI_DATA_WIDTH_10 = 3,
|
||||
IPU_CSI_DATA_WIDTH_16 = 9,
|
||||
};
|
||||
|
||||
/*!
|
||||
* Enumeration of CSI clock modes.
|
||||
*/
|
||||
enum {
|
||||
IPU_CSI_CLK_MODE_GATED_CLK,
|
||||
IPU_CSI_CLK_MODE_NONGATED_CLK,
|
||||
IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
|
||||
IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
|
||||
IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
|
||||
IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
|
||||
IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
|
||||
IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
|
||||
};
|
||||
|
||||
enum {
|
||||
IPU_CSI_MIPI_DI0,
|
||||
IPU_CSI_MIPI_DI1,
|
||||
IPU_CSI_MIPI_DI2,
|
||||
IPU_CSI_MIPI_DI3,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
RGB,
|
||||
YCbCr,
|
||||
YUV
|
||||
} ipu_color_space_t;
|
||||
|
||||
/*!
|
||||
* Enumeration of ADC vertical sync mode.
|
||||
*/
|
||||
typedef enum {
|
||||
VsyncNone,
|
||||
VsyncInternal,
|
||||
VsyncCSI,
|
||||
VsyncExternal
|
||||
} vsync_t;
|
||||
|
||||
typedef enum {
|
||||
DAT,
|
||||
CMD
|
||||
} cmddata_t;
|
||||
|
||||
/*!
|
||||
* Enumeration of ADC display update mode.
|
||||
*/
|
||||
typedef enum {
|
||||
IPU_ADC_REFRESH_NONE,
|
||||
IPU_ADC_AUTO_REFRESH,
|
||||
IPU_ADC_AUTO_REFRESH_SNOOP,
|
||||
IPU_ADC_SNOOPING,
|
||||
} ipu_adc_update_mode_t;
|
||||
|
||||
/*!
|
||||
* Enumeration of ADC display interface types (serial or parallel).
|
||||
*/
|
||||
enum {
|
||||
IPU_ADC_IFC_MODE_SYS80_TYPE1,
|
||||
IPU_ADC_IFC_MODE_SYS80_TYPE2,
|
||||
IPU_ADC_IFC_MODE_SYS68K_TYPE1,
|
||||
IPU_ADC_IFC_MODE_SYS68K_TYPE2,
|
||||
IPU_ADC_IFC_MODE_3WIRE_SERIAL,
|
||||
IPU_ADC_IFC_MODE_4WIRE_SERIAL,
|
||||
IPU_ADC_IFC_MODE_5WIRE_SERIAL_CLK,
|
||||
IPU_ADC_IFC_MODE_5WIRE_SERIAL_CS,
|
||||
};
|
||||
|
||||
enum {
|
||||
IPU_ADC_IFC_WIDTH_8,
|
||||
IPU_ADC_IFC_WIDTH_16,
|
||||
};
|
||||
|
||||
/*!
|
||||
* Enumeration of ADC display interface burst mode.
|
||||
*/
|
||||
enum {
|
||||
IPU_ADC_BURST_WCS,
|
||||
IPU_ADC_BURST_WBLCK,
|
||||
IPU_ADC_BURST_NONE,
|
||||
IPU_ADC_BURST_SERIAL,
|
||||
};
|
||||
|
||||
/*!
|
||||
* Enumeration of ADC display interface RW signal timing modes.
|
||||
*/
|
||||
enum {
|
||||
IPU_ADC_SER_NO_RW,
|
||||
IPU_ADC_SER_RW_BEFORE_RS,
|
||||
IPU_ADC_SER_RW_AFTER_RS,
|
||||
};
|
||||
|
||||
/*!
|
||||
* Bitfield of ADC signal polarities and modes.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned data_pol:1;
|
||||
unsigned clk_pol:1;
|
||||
unsigned cs_pol:1;
|
||||
unsigned rs_pol:1;
|
||||
unsigned addr_pol:1;
|
||||
unsigned read_pol:1;
|
||||
unsigned write_pol:1;
|
||||
unsigned Vsync_pol:1;
|
||||
unsigned burst_pol:1;
|
||||
unsigned burst_mode:2;
|
||||
unsigned ifc_mode:3;
|
||||
unsigned ifc_width:5;
|
||||
unsigned ser_preamble_len:4;
|
||||
unsigned ser_preamble:8;
|
||||
unsigned ser_rw_mode:2;
|
||||
} ipu_adc_sig_cfg_t;
|
||||
|
||||
/*!
|
||||
* Enumeration of ADC template commands.
|
||||
*/
|
||||
enum {
|
||||
RD_DATA,
|
||||
RD_ACK,
|
||||
RD_WAIT,
|
||||
WR_XADDR,
|
||||
WR_YADDR,
|
||||
WR_ADDR,
|
||||
WR_CMND,
|
||||
WR_DATA,
|
||||
};
|
||||
|
||||
/*!
|
||||
* Enumeration of ADC template command flow control.
|
||||
*/
|
||||
enum {
|
||||
SINGLE_STEP,
|
||||
PAUSE,
|
||||
STOP,
|
||||
};
|
||||
|
||||
|
||||
/*Define template constants*/
|
||||
#define ATM_ADDR_RANGE 0x20 /*offset address of DISP */
|
||||
#define TEMPLATE_BUF_SIZE 0x20 /*size of template */
|
||||
|
||||
/*!
|
||||
* Define to create ADC template command entry.
|
||||
*/
|
||||
#define ipu_adc_template_gen(oc, rs, fc, dat) (((rs) << 29) | ((fc) << 27) | \
|
||||
((oc) << 24) | (dat))
|
||||
|
||||
typedef struct {
|
||||
u32 reg;
|
||||
u32 value;
|
||||
} ipu_lpmc_reg_t;
|
||||
|
||||
#define IPU_LPMC_REG_READ 0x80000000L
|
||||
|
||||
#define CSI_MCLK_VF 1
|
||||
#define CSI_MCLK_ENC 2
|
||||
#define CSI_MCLK_RAW 4
|
||||
#define CSI_MCLK_I2C 8
|
||||
|
||||
struct ipu_soc;
|
||||
/* Common IPU API */
|
||||
struct ipu_soc *ipu_get_soc(int id);
|
||||
int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params);
|
||||
void ipu_uninit_channel(struct ipu_soc *ipu, ipu_channel_t channel);
|
||||
void ipu_disable_hsp_clk(struct ipu_soc *ipu);
|
||||
|
||||
static inline bool ipu_can_rotate_in_place(ipu_rotate_mode_t rot)
|
||||
{
|
||||
#ifdef CONFIG_MXC_IPU_V3D
|
||||
return (rot < IPU_ROTATE_HORIZ_FLIP);
|
||||
#else
|
||||
return (rot < IPU_ROTATE_90_RIGHT);
|
||||
#endif
|
||||
}
|
||||
|
||||
int32_t ipu_init_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
|
||||
uint32_t pixel_fmt,
|
||||
uint16_t width, uint16_t height,
|
||||
uint32_t stride,
|
||||
ipu_rotate_mode_t rot_mode,
|
||||
dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
|
||||
dma_addr_t phyaddr_2,
|
||||
uint32_t u_offset, uint32_t v_offset);
|
||||
|
||||
int32_t ipu_update_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
|
||||
uint32_t bufNum, dma_addr_t phyaddr);
|
||||
|
||||
int32_t ipu_update_channel_offset(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
|
||||
uint32_t pixel_fmt,
|
||||
uint16_t width, uint16_t height,
|
||||
uint32_t stride,
|
||||
uint32_t u, uint32_t v,
|
||||
uint32_t vertical_offset, uint32_t horizontal_offset);
|
||||
|
||||
int32_t ipu_get_channel_offset(uint32_t pixel_fmt,
|
||||
uint16_t width, uint16_t height,
|
||||
uint32_t stride,
|
||||
uint32_t u, uint32_t v,
|
||||
uint32_t vertical_offset, uint32_t horizontal_offset,
|
||||
uint32_t *u_offset, uint32_t *v_offset);
|
||||
|
||||
int32_t ipu_select_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
|
||||
ipu_buffer_t type, uint32_t bufNum);
|
||||
int32_t ipu_select_multi_vdi_buffer(struct ipu_soc *ipu, uint32_t bufNum);
|
||||
|
||||
int32_t ipu_link_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel_t dest_ch);
|
||||
int32_t ipu_unlink_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel_t dest_ch);
|
||||
|
||||
int32_t ipu_is_channel_busy(struct ipu_soc *ipu, ipu_channel_t channel);
|
||||
int32_t ipu_check_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
|
||||
uint32_t bufNum);
|
||||
void ipu_clear_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
|
||||
uint32_t bufNum);
|
||||
uint32_t ipu_get_cur_buffer_idx(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type);
|
||||
int32_t ipu_enable_channel(struct ipu_soc *ipu, ipu_channel_t channel);
|
||||
int32_t ipu_disable_channel(struct ipu_soc *ipu, ipu_channel_t channel, bool wait_for_stop);
|
||||
int32_t ipu_swap_channel(struct ipu_soc *ipu, ipu_channel_t from_ch, ipu_channel_t to_ch);
|
||||
uint32_t ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel);
|
||||
|
||||
int32_t ipu_enable_csi(struct ipu_soc *ipu, uint32_t csi);
|
||||
int32_t ipu_disable_csi(struct ipu_soc *ipu, uint32_t csi);
|
||||
|
||||
int ipu_lowpwr_display_enable(void);
|
||||
int ipu_lowpwr_display_disable(void);
|
||||
|
||||
int ipu_enable_irq(struct ipu_soc *ipu, uint32_t irq);
|
||||
void ipu_disable_irq(struct ipu_soc *ipu, uint32_t irq);
|
||||
void ipu_clear_irq(struct ipu_soc *ipu, uint32_t irq);
|
||||
int ipu_request_irq(struct ipu_soc *ipu, uint32_t irq,
|
||||
irqreturn_t(*handler) (int, void *),
|
||||
uint32_t irq_flags, const char *devname, void *dev_id);
|
||||
void ipu_free_irq(struct ipu_soc *ipu, uint32_t irq, void *dev_id);
|
||||
bool ipu_get_irq_status(struct ipu_soc *ipu, uint32_t irq);
|
||||
void ipu_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3]);
|
||||
int32_t ipu_set_channel_bandmode(struct ipu_soc *ipu, ipu_channel_t channel,
|
||||
ipu_buffer_t type, uint32_t band_height);
|
||||
|
||||
/* two stripe calculations */
|
||||
struct stripe_param{
|
||||
unsigned int input_width; /* width of the input stripe */
|
||||
unsigned int output_width; /* width of the output stripe */
|
||||
unsigned int input_column; /* the first column on the input stripe */
|
||||
unsigned int output_column; /* the first column on the output stripe */
|
||||
unsigned int idr;
|
||||
/* inverse downisizing ratio parameter; expressed as a power of 2 */
|
||||
unsigned int irr;
|
||||
/* inverse resizing ratio parameter; expressed as a multiple of 2^-13 */
|
||||
};
|
||||
int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
|
||||
unsigned int output_frame_width,
|
||||
const unsigned int maximal_stripe_width,
|
||||
const unsigned long long cirr,
|
||||
const unsigned int equal_stripes,
|
||||
u32 input_pixelformat,
|
||||
u32 output_pixelformat,
|
||||
struct stripe_param *left,
|
||||
struct stripe_param *right);
|
||||
|
||||
/* SDC API */
|
||||
int32_t ipu_init_sync_panel(struct ipu_soc *ipu, int disp,
|
||||
uint32_t pixel_clk,
|
||||
uint16_t width, uint16_t height,
|
||||
uint32_t pixel_fmt,
|
||||
uint16_t h_start_width, uint16_t h_sync_width,
|
||||
uint16_t h_end_width, uint16_t v_start_width,
|
||||
uint16_t v_sync_width, uint16_t v_end_width,
|
||||
uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig);
|
||||
|
||||
void ipu_uninit_sync_panel(struct ipu_soc *ipu, int disp);
|
||||
|
||||
int32_t ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel, int16_t x_pos,
|
||||
int16_t y_pos);
|
||||
int32_t ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel, int16_t *x_pos,
|
||||
int16_t *y_pos);
|
||||
int32_t ipu_disp_set_global_alpha(struct ipu_soc *ipu, ipu_channel_t channel, bool enable,
|
||||
uint8_t alpha);
|
||||
int32_t ipu_disp_set_color_key(struct ipu_soc *ipu, ipu_channel_t channel, bool enable,
|
||||
uint32_t colorKey);
|
||||
int32_t ipu_disp_set_gamma_correction(struct ipu_soc *ipu, ipu_channel_t channel, bool enable,
|
||||
int constk[], int slopek[]);
|
||||
|
||||
int ipu_init_async_panel(struct ipu_soc *ipu, int disp, int type, uint32_t cycle_time,
|
||||
uint32_t pixel_fmt, ipu_adc_sig_cfg_t sig);
|
||||
void ipu_reset_disp_panel(struct ipu_soc *ipu);
|
||||
|
||||
/* CMOS Sensor Interface API */
|
||||
int32_t ipu_csi_init_interface(struct ipu_soc *ipu, uint16_t width, uint16_t height,
|
||||
uint32_t pixel_fmt, ipu_csi_signal_cfg_t sig);
|
||||
|
||||
int32_t ipu_csi_get_sensor_protocol(struct ipu_soc *ipu, uint32_t csi);
|
||||
|
||||
int32_t ipu_csi_enable_mclk(struct ipu_soc *ipu, int src, bool flag, bool wait);
|
||||
|
||||
static inline int32_t ipu_csi_enable_mclk_if(struct ipu_soc *ipu, int src, uint32_t csi,
|
||||
bool flag, bool wait)
|
||||
{
|
||||
return ipu_csi_enable_mclk(ipu, csi, flag, wait);
|
||||
}
|
||||
|
||||
int ipu_csi_read_mclk_flag(void);
|
||||
|
||||
void ipu_csi_flash_strobe(bool flag);
|
||||
|
||||
void ipu_csi_get_window_size(struct ipu_soc *ipu, uint32_t *width, uint32_t *height, uint32_t csi);
|
||||
|
||||
void ipu_csi_set_window_size(struct ipu_soc *ipu, uint32_t width, uint32_t height, uint32_t csi);
|
||||
|
||||
void ipu_csi_set_window_pos(struct ipu_soc *ipu, uint32_t left, uint32_t top, uint32_t csi);
|
||||
|
||||
uint32_t bytes_per_pixel(uint32_t fmt);
|
||||
|
||||
bool ipu_ch_param_bad_alpha_pos(uint32_t fmt);
|
||||
int ipu_ch_param_get_axi_id(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type);
|
||||
ipu_color_space_t format_to_colorspace(uint32_t fmt);
|
||||
bool ipu_pixel_format_is_gpu_tile(uint32_t fmt);
|
||||
bool ipu_pixel_format_is_split_gpu_tile(uint32_t fmt);
|
||||
bool ipu_pixel_format_is_pre_yuv(uint32_t fmt);
|
||||
bool ipu_pixel_format_is_multiplanar_yuv(uint32_t fmt);
|
||||
|
||||
struct ipuv3_fb_platform_data {
|
||||
char disp_dev[32];
|
||||
u32 interface_pix_fmt;
|
||||
char *mode_str;
|
||||
int default_bpp;
|
||||
bool int_clk;
|
||||
|
||||
/* reserved mem */
|
||||
resource_size_t res_base[2];
|
||||
resource_size_t res_size[2];
|
||||
|
||||
/*
|
||||
* Late init to avoid display channel being
|
||||
* re-initialized as we've probably setup the
|
||||
* channel in bootloader.
|
||||
*/
|
||||
bool late_init;
|
||||
|
||||
/* Enable prefetch engine or not? */
|
||||
bool prefetch;
|
||||
|
||||
/* Enable the PRE resolve engine or not? */
|
||||
bool resolve;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_IPU_V3_H_ */
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2005-2015 Freescale Semiconductor, Inc.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU Lesser General
|
||||
* Public License. You may obtain a copy of the GNU Lesser General
|
||||
* Public License Version 2.1 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/lgpl-license.html
|
||||
* http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @defgroup IPU MXC Image Processing Unit (IPU) Driver
|
||||
*/
|
||||
/*!
|
||||
* @file linux/ipu.h
|
||||
*
|
||||
* @brief This file contains the IPU driver API declarations.
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_IPU_H__
|
||||
#define __LINUX_IPU_H__
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <uapi/linux/ipu.h>
|
||||
|
||||
unsigned int fmt_to_bpp(unsigned int pixelformat);
|
||||
cs_t colorspaceofpixel(int fmt);
|
||||
int need_csc(int ifmt, int ofmt);
|
||||
|
||||
int ipu_queue_task(struct ipu_task *task);
|
||||
int ipu_check_task(struct ipu_task *task);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (C) 2011-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
#ifndef __LINUX_MXC_HDMI_CORE_H_
|
||||
#define __LINUX_MXC_HDMI_CORE_H_
|
||||
|
||||
#include <video/mxc_edid.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#define IRQ_DISABLE_SUCCEED 0
|
||||
#define IRQ_DISABLE_FAIL 1
|
||||
|
||||
bool hdmi_check_overflow(void);
|
||||
|
||||
u8 hdmi_readb(unsigned int reg);
|
||||
void hdmi_writeb(u8 value, unsigned int reg);
|
||||
void hdmi_mask_writeb(u8 data, unsigned int addr, u8 shift, u8 mask);
|
||||
unsigned int hdmi_read4(unsigned int reg);
|
||||
void hdmi_write4(unsigned int value, unsigned int reg);
|
||||
|
||||
void hdmi_irq_init(void);
|
||||
void hdmi_irq_enable(int irq);
|
||||
unsigned int hdmi_irq_disable(int irq);
|
||||
|
||||
void hdmi_set_sample_rate(unsigned int rate);
|
||||
void hdmi_set_dma_mode(unsigned int dma_running);
|
||||
void hdmi_init_clk_regenerator(void);
|
||||
void hdmi_clk_regenerator_update_pixel_clock(u32 pixclock);
|
||||
|
||||
void hdmi_set_edid_cfg(struct mxc_edid_cfg *cfg);
|
||||
void hdmi_get_edid_cfg(struct mxc_edid_cfg *cfg);
|
||||
|
||||
extern int mxc_hdmi_ipu_id;
|
||||
extern int mxc_hdmi_disp_id;
|
||||
|
||||
void hdmi_set_registered(int registered);
|
||||
int hdmi_get_registered(void);
|
||||
int mxc_hdmi_abort_stream(void);
|
||||
int mxc_hdmi_register_audio(struct snd_pcm_substream *substream);
|
||||
void mxc_hdmi_unregister_audio(struct snd_pcm_substream *substream);
|
||||
unsigned int hdmi_set_cable_state(unsigned int state);
|
||||
unsigned int hdmi_set_blank_state(unsigned int state);
|
||||
int check_hdmi_state(void);
|
||||
|
||||
#endif
|
|
@ -244,6 +244,22 @@
|
|||
|
||||
#define IMX6Q_GPR5_L2_CLK_STOP BIT(8)
|
||||
#define IMX6Q_GPR5_ENET_TX_CLK_SEL BIT(9)
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL0_MASK (0x3 << 12)
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL0_SHIFT 12
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL0_MSB 13
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL0_LSB 12
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL0_PRE1_PRG0_CHAN1 (0x0 << 12)
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL0_PRE1_PRG0_CHAN2 (0x1 << 12)
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL0_PRE1_PRG1_CHAN1 (0x2 << 12)
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL0_PRE1_PRG1_CHAN2 (0x3 << 12)
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL1_MASK (0x3 << 14)
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL1_SHIFT 14
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL1_MSB 15
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL1_LSB 14
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL1_PRE2_PRG0_CHAN1 (0x0 << 14)
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL1_PRE2_PRG0_CHAN2 (0x1 << 14)
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL1_PRE2_PRG1_CHAN1 (0x2 << 14)
|
||||
#define IMX6Q_GPR5_PRE_PRG_SEL1_PRE2_PRG1_CHAN2 (0x3 << 14)
|
||||
|
||||
#define IMX6Q_GPR6_IPU1_ID00_WR_QOS_MASK (0xf << 0)
|
||||
#define IMX6Q_GPR6_IPU1_ID01_WR_QOS_MASK (0xf << 4)
|
||||
|
@ -451,6 +467,16 @@
|
|||
#define IMX6SX_GPR12_PCIE_RX_EQ_MASK (0x7 << 0)
|
||||
#define IMX6SX_GPR12_PCIE_RX_EQ_2 (0x2 << 0)
|
||||
|
||||
/* For imx6dl iomux gpr register field definitions */
|
||||
#define IMX6DL_GPR3_LVDS1_MUX_CTL_MASK (0x3 << 8)
|
||||
#define IMX6DL_GPR3_LVDS1_MUX_CTL_IPU1_DI0 (0x0 << 8)
|
||||
#define IMX6DL_GPR3_LVDS1_MUX_CTL_IPU1_DI1 (0x1 << 8)
|
||||
#define IMX6DL_GPR3_LVDS1_MUX_CTL_LCDIF (0x2 << 8)
|
||||
#define IMX6DL_GPR3_LVDS0_MUX_CTL_MASK (0x3 << 6)
|
||||
#define IMX6DL_GPR3_LVDS0_MUX_CTL_IPU1_DI0 (0x0 << 6)
|
||||
#define IMX6DL_GPR3_LVDS0_MUX_CTL_IPU1_DI1 (0x1 << 6)
|
||||
#define IMX6DL_GPR3_LVDS0_MUX_CTL_LCDIF (0x2 << 6)
|
||||
|
||||
/* For imx6ul iomux gpr register field define */
|
||||
#define IMX6UL_GPR1_ENET1_CLK_DIR (0x1 << 17)
|
||||
#define IMX6UL_GPR1_ENET2_CLK_DIR (0x1 << 18)
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2015 Freescale Semiconductor, Inc. All Rights Reserved
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @defgroup IPU MXC Image Processing Unit (IPU) Driver
|
||||
*/
|
||||
/*!
|
||||
* @file uapi/linux/ipu.h
|
||||
*
|
||||
* @brief This file contains the IPU driver API declarations.
|
||||
*
|
||||
* @ingroup IPU
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARCH_IPU_H__
|
||||
#define __ASM_ARCH_IPU_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#ifndef __cplusplus
|
||||
typedef unsigned char bool;
|
||||
#endif
|
||||
#define irqreturn_t int
|
||||
#define dma_addr_t int
|
||||
#define uint32_t unsigned int
|
||||
#define uint16_t unsigned short
|
||||
#define uint8_t unsigned char
|
||||
#define u32 unsigned int
|
||||
#define u8 unsigned char
|
||||
#define __u32 u32
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Enumeration of IPU rotation modes
|
||||
*/
|
||||
typedef enum {
|
||||
/* Note the enum values correspond to BAM value */
|
||||
IPU_ROTATE_NONE = 0,
|
||||
IPU_ROTATE_VERT_FLIP = 1,
|
||||
IPU_ROTATE_HORIZ_FLIP = 2,
|
||||
IPU_ROTATE_180 = 3,
|
||||
IPU_ROTATE_90_RIGHT = 4,
|
||||
IPU_ROTATE_90_RIGHT_VFLIP = 5,
|
||||
IPU_ROTATE_90_RIGHT_HFLIP = 6,
|
||||
IPU_ROTATE_90_LEFT = 7,
|
||||
} ipu_rotate_mode_t;
|
||||
|
||||
/*!
|
||||
* Enumeration of VDI MOTION select
|
||||
*/
|
||||
typedef enum {
|
||||
MED_MOTION = 0,
|
||||
LOW_MOTION = 1,
|
||||
HIGH_MOTION = 2,
|
||||
} ipu_motion_sel;
|
||||
|
||||
/*!
|
||||
* Enumeration of DI ports for ADC.
|
||||
*/
|
||||
typedef enum {
|
||||
DISP0,
|
||||
DISP1,
|
||||
DISP2,
|
||||
DISP3
|
||||
} display_port_t;
|
||||
|
||||
/* IPU Pixel format definitions */
|
||||
/* Four-character-code (FOURCC) */
|
||||
#define fourcc(a, b, c, d)\
|
||||
(((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))
|
||||
|
||||
/*!
|
||||
* @name IPU Pixel Formats
|
||||
*
|
||||
* Pixel formats are defined with ASCII FOURCC code. The pixel format codes are
|
||||
* the same used by V4L2 API.
|
||||
*/
|
||||
|
||||
/*! @{ */
|
||||
/*! @name GPU Tile Formats */
|
||||
/*! @{ */
|
||||
#define IPU_PIX_FMT_GPU32_SB_ST fourcc('5', 'P', '4', 'S') /*!< 32bit split buf 4x4 standard */
|
||||
#define IPU_PIX_FMT_GPU32_SB_SRT fourcc('5', 'P', '4', 'R') /*!< 32bit split buf 4x4 super */
|
||||
#define IPU_PIX_FMT_GPU32_ST fourcc('5', 'I', '4', 'S') /*!< 32bit single buf 4x4 standard */
|
||||
#define IPU_PIX_FMT_GPU32_SRT fourcc('5', 'I', '4', 'R') /*!< 32bit single buf 4x4 super */
|
||||
#define IPU_PIX_FMT_GPU16_SB_ST fourcc('4', 'P', '8', 'S') /*!< 16bit split buf 8x4 standard */
|
||||
#define IPU_PIX_FMT_GPU16_SB_SRT fourcc('4', 'P', '8', 'R') /*!< 16bit split buf 8x4 super */
|
||||
#define IPU_PIX_FMT_GPU16_ST fourcc('4', 'I', '8', 'S') /*!< 16bit single buf 8x4 standard */
|
||||
#define IPU_PIX_FMT_GPU16_SRT fourcc('4', 'I', '8', 'R') /*!< 16bit single buf 8x4 super */
|
||||
|
||||
/*! @{ */
|
||||
/*! @name Generic or Raw Data Formats */
|
||||
/*! @{ */
|
||||
#define IPU_PIX_FMT_GENERIC fourcc('I', 'P', 'U', '0') /*!< IPU Generic Data */
|
||||
#define IPU_PIX_FMT_GENERIC_32 fourcc('I', 'P', 'U', '1') /*!< IPU Generic Data */
|
||||
#define IPU_PIX_FMT_GENERIC_16 fourcc('I', 'P', 'U', '2') /*!< IPU Generic Data */
|
||||
#define IPU_PIX_FMT_LVDS666 fourcc('L', 'V', 'D', '6') /*!< IPU Generic Data */
|
||||
#define IPU_PIX_FMT_LVDS888 fourcc('L', 'V', 'D', '8') /*!< IPU Generic Data */
|
||||
/*! @} */
|
||||
/*! @name RGB Formats */
|
||||
/*! @{ */
|
||||
#define IPU_PIX_FMT_RGB332 fourcc('R', 'G', 'B', '1') /*!< 8 RGB-3-3-2 */
|
||||
#define IPU_PIX_FMT_RGB555 fourcc('R', 'G', 'B', 'O') /*!< 16 RGB-5-5-5 */
|
||||
#define IPU_PIX_FMT_RGB565 fourcc('R', 'G', 'B', 'P') /*!< 1 6 RGB-5-6-5 */
|
||||
#define IPU_PIX_FMT_BGRA4444 fourcc('4', '4', '4', '4') /*!< 16 RGBA-4-4-4-4 */
|
||||
#define IPU_PIX_FMT_BGRA5551 fourcc('5', '5', '5', '1') /*!< 16 RGBA-5-5-5-1 */
|
||||
#define IPU_PIX_FMT_RGB666 fourcc('R', 'G', 'B', '6') /*!< 18 RGB-6-6-6 */
|
||||
#define IPU_PIX_FMT_BGR666 fourcc('B', 'G', 'R', '6') /*!< 18 BGR-6-6-6 */
|
||||
#define IPU_PIX_FMT_BGR24 fourcc('B', 'G', 'R', '3') /*!< 24 BGR-8-8-8 */
|
||||
#define IPU_PIX_FMT_RGB24 fourcc('R', 'G', 'B', '3') /*!< 24 RGB-8-8-8 */
|
||||
#define IPU_PIX_FMT_GBR24 fourcc('G', 'B', 'R', '3') /*!< 24 GBR-8-8-8 */
|
||||
#define IPU_PIX_FMT_BGR32 fourcc('B', 'G', 'R', '4') /*!< 32 BGR-8-8-8-8 */
|
||||
#define IPU_PIX_FMT_BGRA32 fourcc('B', 'G', 'R', 'A') /*!< 32 BGR-8-8-8-8 */
|
||||
#define IPU_PIX_FMT_RGB32 fourcc('R', 'G', 'B', '4') /*!< 32 RGB-8-8-8-8 */
|
||||
#define IPU_PIX_FMT_RGBA32 fourcc('R', 'G', 'B', 'A') /*!< 32 RGB-8-8-8-8 */
|
||||
#define IPU_PIX_FMT_ABGR32 fourcc('A', 'B', 'G', 'R') /*!< 32 ABGR-8-8-8-8 */
|
||||
/*! @} */
|
||||
/*! @name YUV Interleaved Formats */
|
||||
/*! @{ */
|
||||
#define IPU_PIX_FMT_YUYV fourcc('Y', 'U', 'Y', 'V') /*!< 16 YUV 4:2:2 */
|
||||
#define IPU_PIX_FMT_UYVY fourcc('U', 'Y', 'V', 'Y') /*!< 16 YUV 4:2:2 */
|
||||
#define IPU_PIX_FMT_YVYU fourcc('Y', 'V', 'Y', 'U') /*!< 16 YVYU 4:2:2 */
|
||||
#define IPU_PIX_FMT_VYUY fourcc('V', 'Y', 'U', 'Y') /*!< 16 VYYU 4:2:2 */
|
||||
#define IPU_PIX_FMT_Y41P fourcc('Y', '4', '1', 'P') /*!< 12 YUV 4:1:1 */
|
||||
#define IPU_PIX_FMT_YUV444 fourcc('Y', '4', '4', '4') /*!< 24 YUV 4:4:4 */
|
||||
#define IPU_PIX_FMT_VYU444 fourcc('V', '4', '4', '4') /*!< 24 VYU 4:4:4 */
|
||||
#define IPU_PIX_FMT_AYUV fourcc('A', 'Y', 'U', 'V') /*!< 32 AYUV 4:4:4:4 */
|
||||
/* two planes -- one Y, one Cb + Cr interleaved */
|
||||
#define IPU_PIX_FMT_NV12 fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */
|
||||
#define PRE_PIX_FMT_NV21 fourcc('N', 'V', '2', '1') /* 12 Y/CbCr 4:2:0 */
|
||||
#define IPU_PIX_FMT_NV16 fourcc('N', 'V', '1', '6') /* 16 Y/CbCr 4:2:2 */
|
||||
#define PRE_PIX_FMT_NV61 fourcc('N', 'V', '6', '1') /* 16 Y/CbCr 4:2:2 */
|
||||
/* two planes -- 12 tiled Y/CbCr 4:2:0 */
|
||||
#define IPU_PIX_FMT_TILED_NV12 fourcc('T', 'N', 'V', 'P')
|
||||
#define IPU_PIX_FMT_TILED_NV12F fourcc('T', 'N', 'V', 'F')
|
||||
|
||||
/*! @} */
|
||||
/*! @name YUV Planar Formats */
|
||||
/*! @{ */
|
||||
#define IPU_PIX_FMT_GREY fourcc('G', 'R', 'E', 'Y') /*!< 8 Greyscale */
|
||||
#define IPU_PIX_FMT_YVU410P fourcc('Y', 'V', 'U', '9') /*!< 9 YVU 4:1:0 */
|
||||
#define IPU_PIX_FMT_YUV410P fourcc('Y', 'U', 'V', '9') /*!< 9 YUV 4:1:0 */
|
||||
#define IPU_PIX_FMT_YVU420P fourcc('Y', 'V', '1', '2') /*!< 12 YVU 4:2:0 */
|
||||
#define IPU_PIX_FMT_YUV420P fourcc('I', '4', '2', '0') /*!< 12 YUV 4:2:0 */
|
||||
#define IPU_PIX_FMT_YUV420P2 fourcc('Y', 'U', '1', '2') /*!< 12 YUV 4:2:0 */
|
||||
#define IPU_PIX_FMT_YVU422P fourcc('Y', 'V', '1', '6') /*!< 16 YVU 4:2:2 */
|
||||
#define IPU_PIX_FMT_YUV422P fourcc('4', '2', '2', 'P') /*!< 16 YUV 4:2:2 */
|
||||
/* non-interleaved 4:4:4 */
|
||||
#define IPU_PIX_FMT_YUV444P fourcc('4', '4', '4', 'P') /*!< 24 YUV 4:4:4 */
|
||||
/*! @} */
|
||||
#define IPU_PIX_FMT_TILED_NV12_MBALIGN (16)
|
||||
#define TILED_NV12_FRAME_SIZE(w, h) \
|
||||
(ALIGN((w) * (h), SZ_4K) + ALIGN((w) * (h) / 2, SZ_4K))
|
||||
/* IPU device */
|
||||
typedef enum {
|
||||
RGB_CS,
|
||||
YUV_CS,
|
||||
NULL_CS
|
||||
} cs_t;
|
||||
|
||||
struct ipu_pos {
|
||||
u32 x;
|
||||
u32 y;
|
||||
};
|
||||
|
||||
struct ipu_crop {
|
||||
struct ipu_pos pos;
|
||||
u32 w;
|
||||
u32 h;
|
||||
};
|
||||
|
||||
struct ipu_deinterlace {
|
||||
bool enable;
|
||||
u8 motion; /*see ipu_motion_sel*/
|
||||
#define IPU_DEINTERLACE_FIELD_TOP 0
|
||||
#define IPU_DEINTERLACE_FIELD_BOTTOM 1
|
||||
#define IPU_DEINTERLACE_FIELD_MASK \
|
||||
(IPU_DEINTERLACE_FIELD_TOP | IPU_DEINTERLACE_FIELD_BOTTOM)
|
||||
/* deinterlace frame rate double flags */
|
||||
#define IPU_DEINTERLACE_RATE_EN 0x80
|
||||
#define IPU_DEINTERLACE_RATE_FRAME1 0x40
|
||||
#define IPU_DEINTERLACE_RATE_MASK \
|
||||
(IPU_DEINTERLACE_RATE_EN | IPU_DEINTERLACE_RATE_FRAME1)
|
||||
#define IPU_DEINTERLACE_MAX_FRAME 2
|
||||
u8 field_fmt;
|
||||
};
|
||||
|
||||
struct ipu_input {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 format;
|
||||
struct ipu_crop crop;
|
||||
dma_addr_t paddr;
|
||||
|
||||
struct ipu_deinterlace deinterlace;
|
||||
dma_addr_t paddr_n; /*valid when deinterlace enable*/
|
||||
};
|
||||
|
||||
struct ipu_alpha {
|
||||
#define IPU_ALPHA_MODE_GLOBAL 0
|
||||
#define IPU_ALPHA_MODE_LOCAL 1
|
||||
u8 mode;
|
||||
u8 gvalue; /* 0~255 */
|
||||
dma_addr_t loc_alp_paddr;
|
||||
};
|
||||
|
||||
struct ipu_colorkey {
|
||||
bool enable;
|
||||
u32 value; /* RGB 24bit */
|
||||
};
|
||||
|
||||
struct ipu_overlay {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 format;
|
||||
struct ipu_crop crop;
|
||||
struct ipu_alpha alpha;
|
||||
struct ipu_colorkey colorkey;
|
||||
dma_addr_t paddr;
|
||||
};
|
||||
|
||||
struct ipu_output {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 format;
|
||||
u8 rotate;
|
||||
struct ipu_crop crop;
|
||||
dma_addr_t paddr;
|
||||
};
|
||||
|
||||
struct ipu_task {
|
||||
struct ipu_input input;
|
||||
struct ipu_output output;
|
||||
|
||||
bool overlay_en;
|
||||
struct ipu_overlay overlay;
|
||||
|
||||
#define IPU_TASK_PRIORITY_NORMAL 0
|
||||
#define IPU_TASK_PRIORITY_HIGH 1
|
||||
u8 priority;
|
||||
|
||||
#define IPU_TASK_ID_ANY 0
|
||||
#define IPU_TASK_ID_VF 1
|
||||
#define IPU_TASK_ID_PP 2
|
||||
#define IPU_TASK_ID_MAX 3
|
||||
u8 task_id;
|
||||
|
||||
int timeout;
|
||||
};
|
||||
|
||||
enum {
|
||||
IPU_CHECK_OK = 0,
|
||||
IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN = 0x1,
|
||||
IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN = 0x2,
|
||||
IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN = 0x4,
|
||||
IPU_CHECK_ERR_MIN,
|
||||
IPU_CHECK_ERR_INPUT_CROP,
|
||||
IPU_CHECK_ERR_OUTPUT_CROP,
|
||||
IPU_CHECK_ERR_OVERLAY_CROP,
|
||||
IPU_CHECK_ERR_INPUT_OVER_LIMIT,
|
||||
IPU_CHECK_ERR_OV_OUT_NO_FIT,
|
||||
IPU_CHECK_ERR_OVERLAY_WITH_VDI,
|
||||
IPU_CHECK_ERR_PROC_NO_NEED,
|
||||
IPU_CHECK_ERR_SPLIT_INPUTW_OVER,
|
||||
IPU_CHECK_ERR_SPLIT_INPUTH_OVER,
|
||||
IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER,
|
||||
IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER,
|
||||
IPU_CHECK_ERR_SPLIT_WITH_ROT,
|
||||
IPU_CHECK_ERR_NOT_SUPPORT,
|
||||
IPU_CHECK_ERR_NOT16ALIGN,
|
||||
IPU_CHECK_ERR_W_DOWNSIZE_OVER,
|
||||
IPU_CHECK_ERR_H_DOWNSIZE_OVER,
|
||||
};
|
||||
|
||||
/* IOCTL commands */
|
||||
#define IPU_CHECK_TASK _IOWR('I', 0x1, struct ipu_task)
|
||||
#define IPU_QUEUE_TASK _IOW('I', 0x2, struct ipu_task)
|
||||
#define IPU_ALLOC _IOWR('I', 0x3, int)
|
||||
#define IPU_FREE _IOW('I', 0x4, int)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright 2009-2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @defgroup Framebuffer Framebuffer Driver for SDC and ADC.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @file mxc_edid.h
|
||||
*
|
||||
* @brief MXC EDID tools
|
||||
*
|
||||
* @ingroup Framebuffer
|
||||
*/
|
||||
|
||||
#ifndef MXC_EDID_H
|
||||
#define MXC_EDID_H
|
||||
|
||||
#include <linux/fb.h>
|
||||
|
||||
#define FB_VMODE_ASPECT_4_3 0x10
|
||||
#define FB_VMODE_ASPECT_16_9 0x20
|
||||
#define FB_VMODE_ASPECT_MASK (FB_VMODE_ASPECT_4_3 | FB_VMODE_ASPECT_16_9)
|
||||
|
||||
enum cea_audio_coding_types {
|
||||
AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0,
|
||||
AUDIO_CODING_TYPE_LPCM = 1,
|
||||
AUDIO_CODING_TYPE_AC3 = 2,
|
||||
AUDIO_CODING_TYPE_MPEG1 = 3,
|
||||
AUDIO_CODING_TYPE_MP3 = 4,
|
||||
AUDIO_CODING_TYPE_MPEG2 = 5,
|
||||
AUDIO_CODING_TYPE_AACLC = 6,
|
||||
AUDIO_CODING_TYPE_DTS = 7,
|
||||
AUDIO_CODING_TYPE_ATRAC = 8,
|
||||
AUDIO_CODING_TYPE_SACD = 9,
|
||||
AUDIO_CODING_TYPE_EAC3 = 10,
|
||||
AUDIO_CODING_TYPE_DTS_HD = 11,
|
||||
AUDIO_CODING_TYPE_MLP = 12,
|
||||
AUDIO_CODING_TYPE_DST = 13,
|
||||
AUDIO_CODING_TYPE_WMAPRO = 14,
|
||||
AUDIO_CODING_TYPE_RESERVED = 15,
|
||||
};
|
||||
|
||||
struct mxc_hdmi_3d_format {
|
||||
unsigned char vic_order_2d;
|
||||
unsigned char struct_3d;
|
||||
unsigned char detail_3d;
|
||||
unsigned char reserved;
|
||||
};
|
||||
|
||||
struct mxc_edid_cfg {
|
||||
bool cea_underscan;
|
||||
bool cea_basicaudio;
|
||||
bool cea_ycbcr444;
|
||||
bool cea_ycbcr422;
|
||||
bool hdmi_cap;
|
||||
|
||||
/*VSD*/
|
||||
bool vsd_support_ai;
|
||||
bool vsd_dc_48bit;
|
||||
bool vsd_dc_36bit;
|
||||
bool vsd_dc_30bit;
|
||||
bool vsd_dc_y444;
|
||||
bool vsd_dvi_dual;
|
||||
|
||||
bool vsd_cnc0;
|
||||
bool vsd_cnc1;
|
||||
bool vsd_cnc2;
|
||||
bool vsd_cnc3;
|
||||
|
||||
u8 vsd_video_latency;
|
||||
u8 vsd_audio_latency;
|
||||
u8 vsd_I_video_latency;
|
||||
u8 vsd_I_audio_latency;
|
||||
|
||||
u8 physical_address[4];
|
||||
u8 hdmi_vic[64];
|
||||
struct mxc_hdmi_3d_format hdmi_3d_format[64];
|
||||
u16 hdmi_3d_mask_all;
|
||||
u16 hdmi_3d_struct_all;
|
||||
u32 vsd_max_tmdsclk_rate;
|
||||
|
||||
u8 max_channels;
|
||||
u8 sample_sizes;
|
||||
u8 sample_rates;
|
||||
u8 speaker_alloc;
|
||||
};
|
||||
|
||||
int mxc_edid_var_to_vic(struct fb_var_screeninfo *var);
|
||||
int mxc_edid_mode_to_vic(const struct fb_videomode *mode);
|
||||
int mxc_edid_read(struct i2c_adapter *adp, unsigned short addr,
|
||||
unsigned char *edid, struct mxc_edid_cfg *cfg, struct fb_info *fbi);
|
||||
int mxc_edid_parse_ext_blk(unsigned char *edid, struct mxc_edid_cfg *cfg,
|
||||
struct fb_monspecs *specs);
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue