Signed-off-by: Yong Zhi <yong.zhi@xxxxxxxxx> --- drivers/media/pci/intel/ipu3/ipu3-css.c | 515 ++++++++++++++++++++++++++++++++ drivers/media/pci/intel/ipu3/ipu3-css.h | 5 + 2 files changed, 520 insertions(+) create mode 100644 drivers/media/pci/intel/ipu3/ipu3-css.c diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.c b/drivers/media/pci/intel/ipu3/ipu3-css.c new file mode 100644 index 0000000..675be91 --- /dev/null +++ b/drivers/media/pci/intel/ipu3/ipu3-css.c @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2017 Intel Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include "ipu3-css.h" +#include "ipu3-css-fw.h" +#include "ipu3-tables.h" + +/* IRQ configuration */ +#define IMGU_IRQCTRL_IRQ_MASK (IMGU_IRQCTRL_IRQ_SP1 | \ + IMGU_IRQCTRL_IRQ_SP2 | \ + IMGU_IRQCTRL_IRQ_SW_PIN(0) | \ + IMGU_IRQCTRL_IRQ_SW_PIN(1)) + +static void writes(void *mem, ssize_t len, void __iomem *reg) +{ + while (len >= 4) { + writel(*(u32 *)mem, reg); + mem += 4; + reg += 4; + len -= 4; + } +} + +/******************* css hw *******************/ + +/* Wait until register `reg', masked with `mask', becomes `cmp' */ +static int ipu3_css_hw_wait(struct ipu3_css *css, int reg, u32 mask, u32 cmp) +{ + static const unsigned int delay = 1000; + unsigned int maxloops = 1000000 / 10 / delay; + + do { + if ((readl(css->base + reg) & mask) == cmp) + return 0; + usleep_range(delay, 2 * delay); + } while (--maxloops); + + return -EIO; +} + +/* Initialize the IPU3 CSS hardware and associated h/w blocks */ + +int ipu3_css_set_powerup(struct ipu3_css *css) +{ + struct device *dev = css->dev; + void __iomem *const base = css->base; + u32 pm_ctrl, state; + + /* Clear the CSS busy signal */ + readl(base + IMGU_REG_GP_BUSY); + writel(0, base + IMGU_REG_GP_BUSY); + + /* Wait for idle signal */ + if (ipu3_css_hw_wait(css, IMGU_REG_STATE, IMGU_STATE_IDLE_STS, + IMGU_STATE_IDLE_STS)) + dev_warn(dev, "failed to set CSS idle\n"); + + /* Reset the css */ + writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_RESET, + base + IMGU_REG_PM_CTRL); + + usleep_range(200, 300); + + /** Prepare CSS */ + + pm_ctrl = readl(base + IMGU_REG_PM_CTRL); + state = readl(base + IMGU_REG_STATE); + + dev_dbg(dev, "CSS pm_ctrl 0x%x state 0x%x (power %s)\n", + pm_ctrl, state, state & IMGU_STATE_POWER_DOWN ? "down" : "up"); + + /* Power up CSS using wrapper */ + if (state & IMGU_STATE_POWER_DOWN) { + writel(IMGU_PM_CTRL_RACE_TO_HALT | IMGU_PM_CTRL_START, + base + IMGU_REG_PM_CTRL); + if (ipu3_css_hw_wait(css, IMGU_REG_PM_CTRL, + IMGU_PM_CTRL_START, 0)) + dev_warn(dev, "failed to power up CSS\n"); + usleep_range(2000, 3000); + } else { + writel(IMGU_PM_CTRL_RACE_TO_HALT, base + IMGU_REG_PM_CTRL); + } + + /* Set the busy bit */ + writel(readl(base + IMGU_REG_GP_BUSY) | 1, base + IMGU_REG_GP_BUSY); + + return 0; +} + +int ipu3_css_set_powerdown(struct ipu3_css *css) +{ + struct device *dev = css->dev; + void __iomem *const base = css->base; + + /* Clear the CSS busy signal */ + readl(base + IMGU_REG_GP_BUSY); + writel(0, base + IMGU_REG_GP_BUSY); + + /* Wait for idle signal */ + if (ipu3_css_hw_wait(css, IMGU_REG_STATE, IMGU_STATE_IDLE_STS, + IMGU_STATE_IDLE_STS)) + dev_warn(dev, "failed to set CSS idle\n"); + + /* Reset the css */ + writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_CSS_PWRDN, + base + IMGU_REG_PM_CTRL); + + return 0; +} + +static int ipu3_css_hw_init(struct ipu3_css *css) +{ + /* For checking that streaming monitor statuses are valid */ + static const struct { + u32 reg; + u32 mask; + const char *name; + } stream_monitors[] = { + { + IMGU_REG_GP_SP1_STRMON_STAT, + IMGU_GP_STRMON_STAT_ISP_PORT_SP12ISP, + "ISP0 to SP0" + }, { + IMGU_REG_GP_ISP_STRMON_STAT, + IMGU_GP_STRMON_STAT_SP1_PORT_ISP2SP1, + "SP0 to ISP0" + }, { + IMGU_REG_GP_MOD_STRMON_STAT, + IMGU_GP_STRMON_STAT_MOD_PORT_ISP2DMA, + "ISP0 to DMA0" + }, { + IMGU_REG_GP_ISP_STRMON_STAT, + IMGU_GP_STRMON_STAT_ISP_PORT_DMA2ISP, + "DMA0 to ISP0" + }, { + IMGU_REG_GP_MOD_STRMON_STAT, + IMGU_GP_STRMON_STAT_MOD_PORT_CELLS2GDC, + "ISP0 to GDC0" + }, { + IMGU_REG_GP_MOD_STRMON_STAT, + IMGU_GP_STRMON_STAT_MOD_PORT_GDC2CELLS, + "GDC0 to ISP0" + }, { + IMGU_REG_GP_MOD_STRMON_STAT, + IMGU_GP_STRMON_STAT_MOD_PORT_SP12DMA, + "SP0 to DMA0" + }, { + IMGU_REG_GP_SP1_STRMON_STAT, + IMGU_GP_STRMON_STAT_SP1_PORT_DMA2SP1, + "DMA0 to SP0" + }, { + IMGU_REG_GP_MOD_STRMON_STAT, + IMGU_GP_STRMON_STAT_MOD_PORT_CELLS2GDC, + "SP0 to GDC0" + }, { + IMGU_REG_GP_MOD_STRMON_STAT, + IMGU_GP_STRMON_STAT_MOD_PORT_GDC2CELLS, + "GDC0 to SP0" + }, + }; + + static const unsigned int freq = 320; + struct device *dev = css->dev; + void __iomem *const base = css->base; + u32 pm_ctrl, val, i; + + /* Set CSS clock frequency */ + + pm_ctrl = readl(base + IMGU_REG_PM_CTRL); + val = pm_ctrl & ~(IMGU_PM_CTRL_CSS_PWRDN | IMGU_PM_CTRL_RST_AT_EOF); + writel(val, base + IMGU_REG_PM_CTRL); + writel(0, base + IMGU_REG_GP_BUSY); + if (ipu3_css_hw_wait(css, IMGU_REG_STATE, + IMGU_STATE_PWRDNM_FSM_MASK, 0)) + dev_err(dev, "failed to pwrdn CSS\n"); + val = (freq / IMGU_SYSTEM_REQ_FREQ_DIVIDER) & IMGU_SYSTEM_REQ_FREQ_MASK; + writel(val, base + IMGU_REG_SYSTEM_REQ); + writel(1, base + IMGU_REG_GP_BUSY); + writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_HALT, + base + IMGU_REG_PM_CTRL); + if (ipu3_css_hw_wait(css, IMGU_REG_STATE, IMGU_STATE_HALT_STS, + IMGU_STATE_HALT_STS)) + dev_err(dev, "failed to halt CSS\n"); + + writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_START, + base + IMGU_REG_PM_CTRL); + if (ipu3_css_hw_wait(css, IMGU_REG_PM_CTRL, IMGU_PM_CTRL_START, 0)) + dev_err(dev, "failed to start CSS\n"); + writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_UNHALT, + base + IMGU_REG_PM_CTRL); + + val = readl(base + IMGU_REG_PM_CTRL); /* get pm_ctrl */ + val &= ~(IMGU_PM_CTRL_CSS_PWRDN | IMGU_PM_CTRL_RST_AT_EOF); + val |= pm_ctrl & (IMGU_PM_CTRL_CSS_PWRDN | IMGU_PM_CTRL_RST_AT_EOF); + writel(val, base + IMGU_REG_PM_CTRL); + + /* Set MMU L1 table address and flush TLB */ + + writel(css->mmu_l1_addr >> IMGU_MMU_PADDR_SHIFT, + base + IMGU_REG_L1_PHYS); + + /* Set up interrupts */ + + /* + * Enable IRQ on the SP which signals that SP goes to idle + * (aka ready state) and set trigger to pulse + */ + val = readl(base + IMGU_REG_SP_CTRL(0)) | IMGU_CTRL_IRQ_READY; + writel(val, base + IMGU_REG_SP_CTRL(0)); + writel(val | IMGU_CTRL_IRQ_CLEAR, base + IMGU_REG_SP_CTRL(0)); + + /* Enable IRQs from the IMGU wrapper */ + writel(IMGU_REG_INT_CSS_IRQ, base + IMGU_REG_INT_ENABLE); + /* Clear */ + writel(IMGU_REG_INT_CSS_IRQ, base + IMGU_REG_INT_STATUS); + + /* Enable IRQs from main IRQ controller */ + writel(~0, base + IMGU_REG_IRQCTRL_EDGE_NOT_PULSE(IMGU_IRQCTRL_MAIN)); + writel(0, base + IMGU_REG_IRQCTRL_MASK(IMGU_IRQCTRL_MAIN)); + writel(IMGU_IRQCTRL_IRQ_MASK, + base + IMGU_REG_IRQCTRL_EDGE(IMGU_IRQCTRL_MAIN)); + writel(IMGU_IRQCTRL_IRQ_MASK, + base + IMGU_REG_IRQCTRL_ENABLE(IMGU_IRQCTRL_MAIN)); + writel(IMGU_IRQCTRL_IRQ_MASK, + base + IMGU_REG_IRQCTRL_CLEAR(IMGU_IRQCTRL_MAIN)); + writel(IMGU_IRQCTRL_IRQ_MASK, + base + IMGU_REG_IRQCTRL_MASK(IMGU_IRQCTRL_MAIN)); + /* Wait for write complete */ + readl(base + IMGU_REG_IRQCTRL_ENABLE(IMGU_IRQCTRL_MAIN)); + + /* Enable IRQs from SP0 and SP1 controllers */ + for (i = IMGU_IRQCTRL_SP0; i <= IMGU_IRQCTRL_SP1; i++) { + writel(~0, base + IMGU_REG_IRQCTRL_EDGE_NOT_PULSE(i)); + writel(0, base + IMGU_REG_IRQCTRL_MASK(i)); + writel(IMGU_IRQCTRL_IRQ_MASK, base + IMGU_REG_IRQCTRL_EDGE(i)); + writel(IMGU_IRQCTRL_IRQ_MASK, + base + IMGU_REG_IRQCTRL_ENABLE(i)); + writel(IMGU_IRQCTRL_IRQ_MASK, base + IMGU_REG_IRQCTRL_CLEAR(i)); + writel(IMGU_IRQCTRL_IRQ_MASK, base + IMGU_REG_IRQCTRL_MASK(i)); + /* Wait for write complete */ + readl(base + IMGU_REG_IRQCTRL_ENABLE(i)); + } + + /* Set instruction cache address and inv bit for ISP, SP, and SP1 */ + for (i = 0; i < IMGU_NUM_SP; i++) { + struct imgu_fw_info *bi = + &css->fwp->binary_header[css->fw_sp[i]]; + + writel(css->binary[css->fw_sp[i]].daddr, + base + IMGU_REG_SP_ICACHE_ADDR(bi->type)); + writel(readl(base + IMGU_REG_SP_CTRL(bi->type)) | + IMGU_CTRL_ICACHE_INV, + base + IMGU_REG_SP_CTRL(bi->type)); + } + writel(css->binary[css->fw_bl].daddr, base + IMGU_REG_ISP_ICACHE_ADDR); + writel(readl(base + IMGU_REG_ISP_CTRL) | IMGU_CTRL_ICACHE_INV, + base + IMGU_REG_ISP_CTRL); + + /* Check that IMGU hardware is ready */ + + if (!(readl(base + IMGU_REG_SP_CTRL(0)) & IMGU_CTRL_IDLE)) { + dev_err(dev, "SP is not idle\n"); + return -EIO; + } + if (!(readl(base + IMGU_REG_ISP_CTRL) & IMGU_CTRL_IDLE)) { + dev_err(dev, "ISP is not idle\n"); + return -EIO; + } + + for (i = 0; i < ARRAY_SIZE(stream_monitors); i++) { + val = readl(base + stream_monitors[i].reg); + if (val & stream_monitors[i].mask) { + dev_err(dev, "error: Stream monitor %s is valid\n", + stream_monitors[i].name); + return -EIO; + } + } + + /* Initialize GDC with default values */ + + for (i = 0; i < ARRAY_SIZE(ipu3_css_gdc_lut[0]); i++) { + u32 val0 = ipu3_css_gdc_lut[0][i] & IMGU_GDC_LUT_MASK; + u32 val1 = ipu3_css_gdc_lut[1][i] & IMGU_GDC_LUT_MASK; + u32 val2 = ipu3_css_gdc_lut[2][i] & IMGU_GDC_LUT_MASK; + u32 val3 = ipu3_css_gdc_lut[3][i] & IMGU_GDC_LUT_MASK; + + writel(val0 | (val1 << 16), + base + IMGU_REG_GDC_LUT_BASE + i * 8); + writel(val2 | (val3 << 16), + base + IMGU_REG_GDC_LUT_BASE + i * 8 + 4); + }; + + return 0; +} + +/* Boot the given IPU3 CSS SP */ +static int ipu3_css_hw_start_sp(struct ipu3_css *css, int sp) +{ + void __iomem *const base = css->base; + struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[sp]]; + struct imgu_abi_sp_init_dmem_cfg dmem_cfg = { + .ddr_data_addr = css->binary[css->fw_sp[sp]].daddr + + bi->blob.data_source, + .dmem_data_addr = bi->blob.data_target, + .dmem_bss_addr = bi->blob.bss_target, + .data_size = bi->blob.data_size, + .bss_size = bi->blob.bss_size, + .sp_id = sp, + }; + + writes(&dmem_cfg, sizeof(dmem_cfg), base + + IMGU_REG_SP_DMEM_BASE(sp) + bi->info.sp.init_dmem_data); + + writel(bi->info.sp.sp_entry, base + IMGU_REG_SP_START_ADDR(sp)); + + writel(readl(base + IMGU_REG_SP_CTRL(sp)) + | IMGU_CTRL_START | IMGU_CTRL_RUN, base + IMGU_REG_SP_CTRL(sp)); + + if (ipu3_css_hw_wait(css, IMGU_REG_SP_DMEM_BASE(sp) + + bi->info.sp.sw_state, + ~0, IMGU_ABI_SP_SWSTATE_INITIALIZED)) + return -EIO; + + return 0; +} + +/* Start the IPU3 CSS ImgU (Imaging Unit) and all the SPs */ +static int ipu3_css_hw_start(struct ipu3_css *css) +{ + static const u32 event_mask = + ((1 << IMGU_ABI_EVTTYPE_OUT_FRAME_DONE) | + (1 << IMGU_ABI_EVTTYPE_2ND_OUT_FRAME_DONE) | + (1 << IMGU_ABI_EVTTYPE_VF_OUT_FRAME_DONE) | + (1 << IMGU_ABI_EVTTYPE_2ND_VF_OUT_FRAME_DONE) | + (1 << IMGU_ABI_EVTTYPE_3A_STATS_DONE) | + (1 << IMGU_ABI_EVTTYPE_DIS_STATS_DONE) | + (1 << IMGU_ABI_EVTTYPE_PIPELINE_DONE) | + (1 << IMGU_ABI_EVTTYPE_FRAME_TAGGED) | + (1 << IMGU_ABI_EVTTYPE_INPUT_FRAME_DONE) | + (1 << IMGU_ABI_EVTTYPE_METADATA_DONE) | + (1 << IMGU_ABI_EVTTYPE_LACE_STATS_DONE) | + (1 << IMGU_ABI_EVTTYPE_ACC_STAGE_COMPLETE)) + << IMGU_ABI_SP_COMM_EVENT_IRQ_MASK_OR_SHIFT; + + void __iomem *const base = css->base; + struct imgu_fw_info *bi, *bl = &css->fwp->binary_header[css->fw_bl]; + unsigned int i; + + writel(IMGU_TLB_INVALIDATE, base + IMGU_REG_TLB_INVALIDATE); + + /* Start bootloader */ + + writel(IMGU_ABI_BL_SWSTATE_BUSY, + base + IMGU_REG_ISP_DMEM_BASE + bl->info.bl.sw_state); + writel(IMGU_NUM_SP, + base + IMGU_REG_ISP_DMEM_BASE + bl->info.bl.num_dma_cmds); + + for (i = 0; i < IMGU_NUM_SP; i++) { + int j = IMGU_NUM_SP - i - 1; /* load sp1 first, then sp0 */ + struct imgu_fw_info *sp = + &css->fwp->binary_header[css->fw_sp[j]]; + struct imgu_abi_bl_dma_cmd_entry dma_cmd = { + .src_addr = css->binary[css->fw_sp[j]].daddr + + sp->blob.text_source, + .size = sp->blob.text_size, + .dst_type = IMGU_ABI_BL_DMACMD_TYPE_SP_PMEM, + .dst_addr = IMGU_SP_PMEM_BASE(j), + }; + + writes(&dma_cmd, sizeof(dma_cmd), + base + IMGU_REG_ISP_DMEM_BASE + i * sizeof(dma_cmd) + + bl->info.bl.dma_cmd_list); + } + + writel(bl->info.bl.bl_entry, base + IMGU_REG_ISP_START_ADDR); + + writel(readl(base + IMGU_REG_ISP_CTRL) + | IMGU_CTRL_START | IMGU_CTRL_RUN, base + IMGU_REG_ISP_CTRL); + if (ipu3_css_hw_wait(css, IMGU_REG_ISP_DMEM_BASE + bl->info.bl.sw_state, + ~0, IMGU_ABI_BL_SWSTATE_OK)) { + dev_err(css->dev, "failed to start bootloader\n"); + return -EIO; + } + + /* Start ISP */ + + memset(css->xmem_sp_group_ptrs.vaddr, 0, + sizeof(struct imgu_abi_sp_group)); + dma_sync_single_for_device(css->dev, + css->xmem_sp_group_ptrs.daddr, + sizeof(struct imgu_abi_sp_group), DMA_TO_DEVICE); + + bi = &css->fwp->binary_header[css->fw_sp[0]]; + + writel(css->xmem_sp_group_ptrs.daddr, + base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.per_frame_data); + + writel(IMGU_ABI_SP_SWSTATE_TERMINATED, + base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.sw_state); + writel(1, base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.invalidate_tlb); + + if (ipu3_css_hw_start_sp(css, 0)) + return -EIO; + + writel(0, base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.isp_started); + writel(0, base + IMGU_REG_SP_DMEM_BASE(0) + + bi->info.sp.host_sp_queues_initialized); + writel(0, base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.sleep_mode); + writel(0, base + IMGU_REG_SP_DMEM_BASE(0) + bi->info.sp.invalidate_tlb); + writel(IMGU_ABI_SP_COMM_COMMAND_READY, base + IMGU_REG_SP_DMEM_BASE(0) + + bi->info.sp.host_sp_com + IMGU_ABI_SP_COMM_COMMAND); + + /* Enable all events for all queues */ + + for (i = 0; i < IPU3_CSS_PIPE_ID_NUM; i++) + writel(event_mask, base + IMGU_REG_SP_DMEM_BASE(0) + + bi->info.sp.host_sp_com + + IMGU_ABI_SP_COMM_EVENT_IRQ_MASK(i)); + writel(1, base + IMGU_REG_SP_DMEM_BASE(0) + + bi->info.sp.host_sp_queues_initialized); + + /* Start SP1 */ + + bi = &css->fwp->binary_header[css->fw_sp[1]]; + + writel(IMGU_ABI_SP_SWSTATE_TERMINATED, + base + IMGU_REG_SP_DMEM_BASE(1) + bi->info.sp.sw_state); + + if (ipu3_css_hw_start_sp(css, 1)) + return -EIO; + + writel(IMGU_ABI_SP_COMM_COMMAND_READY, base + IMGU_REG_SP_DMEM_BASE(1) + + bi->info.sp.host_sp_com + IMGU_ABI_SP_COMM_COMMAND); + + return 0; +} + +static void ipu3_css_hw_cleanup(struct ipu3_css *css) +{ + void __iomem *const base = css->base; + + /** Reset CSS **/ + + /* Clear the CSS busy signal */ + readl(base + IMGU_REG_GP_BUSY); + writel(0, base + IMGU_REG_GP_BUSY); + + /* Wait for idle signal */ + if (ipu3_css_hw_wait(css, IMGU_REG_STATE, IMGU_STATE_IDLE_STS, + IMGU_STATE_IDLE_STS)) + dev_err(css->dev, "failed to shut down hw cleanly\n"); + + /* Reset the css */ + writel(readl(base + IMGU_REG_PM_CTRL) | IMGU_PM_CTRL_FORCE_RESET, + base + IMGU_REG_PM_CTRL); + + usleep_range(200, 300); +} + +int ipu3_css_irq_ack(struct ipu3_css *css) +{ + static const int NUM_SWIRQS = 3; + struct imgu_fw_info *bi = &css->fwp->binary_header[css->fw_sp[0]]; + void __iomem *const base = css->base; + u32 irq_status[IMGU_IRQCTRL_NUM]; + int i; + + u32 imgu_status = readl(base + IMGU_REG_INT_STATUS); + + for (i = 0; i < IMGU_IRQCTRL_NUM; i++) + irq_status[i] = readl(base + IMGU_REG_IRQCTRL_STATUS(i)); + + for (i = 0; i < NUM_SWIRQS; i++) { + if (irq_status[IMGU_IRQCTRL_SP0] & IMGU_IRQCTRL_IRQ_SW_PIN(i)) { + /* SP SW interrupt */ + u32 cnt = readl(base + IMGU_REG_SP_DMEM_BASE(0) + + bi->info.sp.output); + u32 val = readl(base + IMGU_REG_SP_DMEM_BASE(0) + + bi->info.sp.output + 4 + 4 * i); + + dev_dbg(css->dev, "%s: swirq %i cnt %i val 0x%x\n", + __func__, i, cnt, val); + } + } + + for (i = IMGU_IRQCTRL_NUM - 1; i >= 0; i--) + if (irq_status[i]) { + writel(irq_status[i], base + IMGU_REG_IRQCTRL_CLEAR(i)); + /* Wait for write to complete */ + readl(base + IMGU_REG_IRQCTRL_ENABLE(i)); + } + writel(imgu_status, base + IMGU_REG_INT_STATUS); + + dev_dbg(css->dev, "%s: imgu 0x%x main 0x%x sp0 0x%x sp1 0x%x\n", + __func__, + imgu_status, irq_status[IMGU_IRQCTRL_MAIN], + irq_status[IMGU_IRQCTRL_SP0], irq_status[IMGU_IRQCTRL_SP1]); + + if (!imgu_status && !irq_status[IMGU_IRQCTRL_MAIN]) + return -ENOMSG; + + return 0; +} diff --git a/drivers/media/pci/intel/ipu3/ipu3-css.h b/drivers/media/pci/intel/ipu3/ipu3-css.h index 6416750..364d490 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-css.h +++ b/drivers/media/pci/intel/ipu3/ipu3-css.h @@ -143,4 +143,9 @@ struct ipu3_css { struct v4l2_rect rect[IPU3_CSS_RECTS]; }; +/******************* css hw *******************/ +int ipu3_css_set_powerup(struct ipu3_css *css); +int ipu3_css_set_powerdown(struct ipu3_css *css); +int ipu3_css_irq_ack(struct ipu3_css *css); + #endif -- 2.7.4