/* * ipipeif_enable - Enable/Disable IPIPEIF. * @enable: enable flag * */ static void ipipeif_enable(struct iss_ipipeif_device *ipipeif, u8 enable) { struct iss_device *iss = to_iss_device(ipipeif); iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SYNCEN, ISIF_SYNCEN_SYEN, enable ? ISIF_SYNCEN_SYEN : 0); }
/* * ipipe_enable - Enable/Disable IPIPE. * @enable: enable flag * */ static void ipipe_enable(struct iss_ipipe_device *ipipe, u8 enable) { struct iss_device *iss = to_iss_device(ipipe); iss_reg_update(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_EN, IPIPE_SRC_EN_EN, enable ? IPIPE_SRC_EN_EN : 0); }
static void __iss_isp_subclk_update(struct iss_device *iss) { u32 clk = 0; if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_ISIF) clk |= ISP5_CTRL_ISIF_CLK_ENABLE; if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_H3A) clk |= ISP5_CTRL_H3A_CLK_ENABLE; if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_RSZ) clk |= ISP5_CTRL_RSZ_CLK_ENABLE; if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPE) clk |= ISP5_CTRL_IPIPE_CLK_ENABLE; if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPEIF) clk |= ISP5_CTRL_IPIPEIF_CLK_ENABLE; if (clk) clk |= ISP5_CTRL_BL_CLK_ENABLE; iss_reg_update(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL, ISS_ISP5_CLKCTRL_MASK, clk); }
static int __iss_subclk_update(struct iss_device *iss) { u32 clk = 0; int ret = 0, timeout = 1000; if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_A) clk |= ISS_CLKCTRL_CSI2_A; if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_B) clk |= ISS_CLKCTRL_CSI2_B; if (iss->subclk_resources & OMAP4_ISS_SUBCLK_ISP) clk |= ISS_CLKCTRL_ISP; iss_reg_update(iss, OMAP4_ISS_MEM_TOP, ISS_CLKCTRL, ISS_CLKCTRL_MASK, clk); /* Wait for HW assertion */ while (--timeout > 0) { udelay(1); if ((iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_CLKSTAT) & ISS_CLKCTRL_MASK) == clk) break; } if (!timeout) ret = -EBUSY; return ret; }
static int iss_isp_reset(struct iss_device *iss) { unsigned int timeout; /* Fist, ensure that the ISP is IDLE (no transactions happening) */ iss_reg_update(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG, ISP5_SYSCONFIG_STANDBYMODE_MASK, ISP5_SYSCONFIG_STANDBYMODE_SMART); iss_reg_set(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL, ISP5_CTRL_MSTANDBY); timeout = iss_poll_condition_timeout( iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL) & ISP5_CTRL_MSTANDBY_WAIT, 1000000, 1000, 1500); if (timeout) { dev_err(iss->dev, "ISP5 standby timeout\n"); return -ETIMEDOUT; } /* Now finally, do the reset */ iss_reg_set(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG, ISP5_SYSCONFIG_SOFTRESET); timeout = iss_poll_condition_timeout( !(iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG) & ISP5_SYSCONFIG_SOFTRESET), 1000000, 1000, 1500); if (timeout) { dev_err(iss->dev, "ISP5 reset timeout\n"); return -ETIMEDOUT; } return 0; }
/* * csi2_if_enable - Enable CSI2 Receiver interface. * @enable: enable flag * */ static void csi2_if_enable(struct iss_csi2_device *csi2, u8 enable) { struct iss_csi2_ctrl_cfg *currctrl = &csi2->ctrl; iss_reg_update(csi2->iss, csi2->regs1, CSI2_CTRL, CSI2_CTRL_IF_EN, enable ? CSI2_CTRL_IF_EN : 0); currctrl->if_enable = enable; }
/* * csi2_ctx_config - CSI2 context configuration. * @ctx: context configuration * */ static void csi2_ctx_config(struct iss_csi2_device *csi2, struct iss_csi2_ctx_cfg *ctx) { u32 reg; /* Set up CSI2_CTx_CTRL1 */ if (ctx->eof_enabled) reg = CSI2_CTX_CTRL1_EOF_EN; if (ctx->eol_enabled) reg |= CSI2_CTX_CTRL1_EOL_EN; if (ctx->checksum_enabled) reg |= CSI2_CTX_CTRL1_CS_EN; iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL1(ctx->ctxnum), reg); /* Set up CSI2_CTx_CTRL2 */ reg = ctx->virtual_id << CSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT; reg |= ctx->format_id << CSI2_CTX_CTRL2_FORMAT_SHIFT; if (ctx->dpcm_decompress && ctx->dpcm_predictor) reg |= CSI2_CTX_CTRL2_DPCM_PRED; if (is_usr_def_mapping(ctx->format_id)) reg |= 2 << CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT; iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL2(ctx->ctxnum), reg); /* Set up CSI2_CTx_CTRL3 */ iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL3(ctx->ctxnum), ctx->alpha << CSI2_CTX_CTRL3_ALPHA_SHIFT); /* Set up CSI2_CTx_DAT_OFST */ iss_reg_update(csi2->iss, csi2->regs1, CSI2_CTX_DAT_OFST(ctx->ctxnum), CSI2_CTX_DAT_OFST_MASK, ctx->data_offset); iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_PING_ADDR(ctx->ctxnum), ctx->ping_addr); iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_PONG_ADDR(ctx->ctxnum), ctx->pong_addr); }
/* * omap4iss_csi2_reset - Resets the CSI2 module. * * Must be called with the phy lock held. * * Returns 0 if successful, or -EBUSY if power command didn't respond. */ int omap4iss_csi2_reset(struct iss_csi2_device *csi2) { unsigned int timeout; if (!csi2->available) return -ENODEV; if (csi2->phy->phy_in_use) return -EBUSY; iss_reg_set(csi2->iss, csi2->regs1, CSI2_SYSCONFIG, CSI2_SYSCONFIG_SOFT_RESET); timeout = iss_poll_condition_timeout( iss_reg_read(csi2->iss, csi2->regs1, CSI2_SYSSTATUS) & CSI2_SYSSTATUS_RESET_DONE, 500, 100, 200); if (timeout) { dev_err(csi2->iss->dev, "CSI2: Soft reset timeout!\n"); return -EBUSY; } iss_reg_set(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_CFG, CSI2_COMPLEXIO_CFG_RESET_CTRL); timeout = iss_poll_condition_timeout( iss_reg_read(csi2->iss, csi2->phy->phy_regs, REGISTER1) & REGISTER1_RESET_DONE_CTRLCLK, 10000, 100, 500); if (timeout) { dev_err(csi2->iss->dev, "CSI2: CSI2_96M_FCLK reset timeout!\n"); return -EBUSY; } iss_reg_update(csi2->iss, csi2->regs1, CSI2_SYSCONFIG, CSI2_SYSCONFIG_MSTANDBY_MODE_MASK | CSI2_SYSCONFIG_AUTO_IDLE, CSI2_SYSCONFIG_MSTANDBY_MODE_NO); return 0; }
static void ipipeif_configure(struct iss_ipipeif_device *ipipeif) { struct iss_device *iss = to_iss_device(ipipeif); const struct iss_format_info *info; struct v4l2_mbus_framefmt *format; u32 isif_ccolp = 0; omap4iss_configure_bridge(iss, ipipeif->input); /* IPIPEIF_PAD_SINK */ format = &ipipeif->formats[IPIPEIF_PAD_SINK]; /* IPIPEIF with YUV422 input from ISIF */ iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG1, IPIPEIF_CFG1_INPSRC1_MASK | IPIPEIF_CFG1_INPSRC2_MASK); /* Select ISIF/IPIPEIF input format */ switch (format->code) { case V4L2_MBUS_FMT_UYVY8_1X16: case V4L2_MBUS_FMT_YUYV8_1X16: iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_MODESET, ISIF_MODESET_CCDMD | ISIF_MODESET_INPMOD_MASK | ISIF_MODESET_CCDW_MASK, ISIF_MODESET_INPMOD_YCBCR16); iss_reg_update(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG2, IPIPEIF_CFG2_YUV8, IPIPEIF_CFG2_YUV16); break; case V4L2_MBUS_FMT_SGRBG10_1X10: isif_ccolp = ISIF_CCOLP_CP0_F0_GR | ISIF_CCOLP_CP1_F0_R | ISIF_CCOLP_CP2_F0_B | ISIF_CCOLP_CP3_F0_GB; goto cont_raw; case V4L2_MBUS_FMT_SRGGB10_1X10: isif_ccolp = ISIF_CCOLP_CP0_F0_R | ISIF_CCOLP_CP1_F0_GR | ISIF_CCOLP_CP2_F0_GB | ISIF_CCOLP_CP3_F0_B; goto cont_raw; case V4L2_MBUS_FMT_SBGGR10_1X10: isif_ccolp = ISIF_CCOLP_CP0_F0_B | ISIF_CCOLP_CP1_F0_GB | ISIF_CCOLP_CP2_F0_GR | ISIF_CCOLP_CP3_F0_R; goto cont_raw; case V4L2_MBUS_FMT_SGBRG10_1X10: isif_ccolp = ISIF_CCOLP_CP0_F0_GB | ISIF_CCOLP_CP1_F0_B | ISIF_CCOLP_CP2_F0_R | ISIF_CCOLP_CP3_F0_GR; cont_raw: iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG2, IPIPEIF_CFG2_YUV16); iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_MODESET, ISIF_MODESET_CCDMD | ISIF_MODESET_INPMOD_MASK | ISIF_MODESET_CCDW_MASK, ISIF_MODESET_INPMOD_RAW | ISIF_MODESET_CCDW_2BIT); info = omap4iss_video_format_info(format->code); iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CGAMMAWD, ISIF_CGAMMAWD_GWDI_MASK, ISIF_CGAMMAWD_GWDI(info->bpp)); /* Set RAW Bayer pattern */ iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CCOLP, isif_ccolp); break; } iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SPH, 0 & ISIF_SPH_MASK); iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_LNH, (format->width - 1) & ISIF_LNH_MASK); iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_LNV, (format->height - 1) & ISIF_LNV_MASK); /* Generate ISIF0 on the last line of the image */ iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_VDINT(0), format->height - 1); /* IPIPEIF_PAD_SOURCE_ISIF_SF */ format = &ipipeif->formats[IPIPEIF_PAD_SOURCE_ISIF_SF]; iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_HSIZE, (ipipeif->video_out.bpl_value >> 5) & ISIF_HSIZE_HSIZE_MASK); /* IPIPEIF_PAD_SOURCE_VP */ /* Do nothing? */ }
static int iss_probe(struct platform_device *pdev) { struct iss_platform_data *pdata = pdev->dev.platform_data; struct iss_device *iss; unsigned int i; int ret; if (!pdata) return -EINVAL; iss = devm_kzalloc(&pdev->dev, sizeof(*iss), GFP_KERNEL); if (!iss) return -ENOMEM; mutex_init(&iss->iss_mutex); iss->dev = &pdev->dev; iss->pdata = pdata; iss->raw_dmamask = DMA_BIT_MASK(32); iss->dev->dma_mask = &iss->raw_dmamask; iss->dev->coherent_dma_mask = DMA_BIT_MASK(32); platform_set_drvdata(pdev, iss); /* * TODO: When implementing DT support switch to syscon regmap lookup by * phandle. */ iss->syscon = syscon_regmap_lookup_by_compatible("syscon"); if (IS_ERR(iss->syscon)) { ret = PTR_ERR(iss->syscon); goto error; } /* Clocks */ ret = iss_map_mem_resource(pdev, iss, OMAP4_ISS_MEM_TOP); if (ret < 0) goto error; ret = iss_get_clocks(iss); if (ret < 0) goto error; if (!omap4iss_get(iss)) goto error; ret = iss_reset(iss); if (ret < 0) goto error_iss; iss->revision = iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_REVISION); dev_info(iss->dev, "Revision %08x found\n", iss->revision); for (i = 1; i < OMAP4_ISS_MEM_LAST; i++) { ret = iss_map_mem_resource(pdev, iss, i); if (ret) goto error_iss; } /* Configure BTE BW_LIMITER field to max recommended value (1 GB) */ iss_reg_update(iss, OMAP4_ISS_MEM_BTE, BTE_CTRL, BTE_CTRL_BW_LIMITER_MASK, 18 << BTE_CTRL_BW_LIMITER_SHIFT); /* Perform ISP reset */ ret = omap4iss_subclk_enable(iss, OMAP4_ISS_SUBCLK_ISP); if (ret < 0) goto error_iss; ret = iss_isp_reset(iss); if (ret < 0) goto error_iss; dev_info(iss->dev, "ISP Revision %08x found\n", iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_REVISION)); /* Interrupt */ ret = platform_get_irq(pdev, 0); if (ret <= 0) { dev_err(iss->dev, "No IRQ resource\n"); ret = -ENODEV; goto error_iss; } iss->irq_num = ret; if (devm_request_irq(iss->dev, iss->irq_num, iss_isr, IRQF_SHARED, "OMAP4 ISS", iss)) { dev_err(iss->dev, "Unable to request IRQ\n"); ret = -EINVAL; goto error_iss; } /* Entities */ ret = iss_initialize_modules(iss); if (ret < 0) goto error_iss; ret = iss_register_entities(iss); if (ret < 0) goto error_modules; ret = media_entity_enum_init(&iss->crashed, &iss->media_dev); if (ret) goto error_entities; ret = iss_create_links(iss); if (ret < 0) goto error_entities; omap4iss_put(iss); return 0; error_entities: iss_unregister_entities(iss); media_entity_enum_cleanup(&iss->crashed); error_modules: iss_cleanup_modules(iss); error_iss: omap4iss_put(iss); error: platform_set_drvdata(pdev, NULL); mutex_destroy(&iss->iss_mutex); return ret; }
static int iss_probe(struct platform_device *pdev) { struct iss_platform_data *pdata = pdev->dev.platform_data; struct iss_device *iss; unsigned int i; int ret; if (pdata == NULL) return -EINVAL; iss = devm_kzalloc(&pdev->dev, sizeof(*iss), GFP_KERNEL); if (!iss) { dev_err(&pdev->dev, "Could not allocate memory\n"); return -ENOMEM; } mutex_init(&iss->iss_mutex); iss->dev = &pdev->dev; iss->pdata = pdata; iss->raw_dmamask = DMA_BIT_MASK(32); iss->dev->dma_mask = &iss->raw_dmamask; iss->dev->coherent_dma_mask = DMA_BIT_MASK(32); platform_set_drvdata(pdev, iss); /* Clocks */ ret = iss_map_mem_resource(pdev, iss, OMAP4_ISS_MEM_TOP); if (ret < 0) goto error; ret = iss_get_clocks(iss); if (ret < 0) goto error; if (omap4iss_get(iss) == NULL) goto error; ret = iss_reset(iss); if (ret < 0) goto error_iss; iss->revision = iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_REVISION); dev_info(iss->dev, "Revision %08x found\n", iss->revision); for (i = 1; i < OMAP4_ISS_MEM_LAST; i++) { ret = iss_map_mem_resource(pdev, iss, i); if (ret) goto error_iss; } /* Configure BTE BW_LIMITER field to max recommended value (1 GB) */ iss_reg_update(iss, OMAP4_ISS_MEM_BTE, BTE_CTRL, BTE_CTRL_BW_LIMITER_MASK, 18 << BTE_CTRL_BW_LIMITER_SHIFT); /* Perform ISP reset */ ret = omap4iss_subclk_enable(iss, OMAP4_ISS_SUBCLK_ISP); if (ret < 0) goto error_iss; ret = iss_isp_reset(iss); if (ret < 0) goto error_iss; dev_info(iss->dev, "ISP Revision %08x found\n", iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_REVISION)); /* Interrupt */ iss->irq_num = platform_get_irq(pdev, 0); if (iss->irq_num <= 0) { dev_err(iss->dev, "No IRQ resource\n"); ret = -ENODEV; goto error_iss; } if (devm_request_irq(iss->dev, iss->irq_num, iss_isr, IRQF_SHARED, "OMAP4 ISS", iss)) { dev_err(iss->dev, "Unable to request IRQ\n"); ret = -EINVAL; goto error_iss; } /* Entities */ ret = iss_initialize_modules(iss); if (ret < 0) goto error_iss; ret = iss_register_entities(iss); if (ret < 0) goto error_modules; omap4iss_put(iss); return 0; error_modules: iss_cleanup_modules(iss); error_iss: omap4iss_put(iss); error: platform_set_drvdata(pdev, NULL); mutex_destroy(&iss->iss_mutex); return ret; }