Lines Matching +full:csi +full:- +full:2
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2012-2014 Mentor Graphics Inc.
4 * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
15 #include <uapi/linux/v4l2-mediabus.h>
17 #include <linux/clk-provider.h>
20 #include "ipu-prv.h"
32 /* CSI Register Offsets */
55 /* CSI Register Fields */
60 #define CSI_SENS_CONF_DATA_FMT_YUV422_UYVY 2L
69 #define CSI_SENS_CONF_DATA_POL_SHIFT 2
86 #define CSI_DATA_DEST_IC 2
116 /* MIPI CSI-2 data types */
133 * Bitfield of CSI bus signal polarities and modes.
153 * Enumeration of CSI data bus widths.
164 * Enumeration of CSI clock modes.
177 static inline u32 ipu_csi_read(struct ipu_csi *csi, unsigned offset) in ipu_csi_read() argument
179 return readl(csi->base + offset); in ipu_csi_read()
182 static inline void ipu_csi_write(struct ipu_csi *csi, u32 value, in ipu_csi_write() argument
185 writel(value, csi->base + offset); in ipu_csi_write()
192 static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk, in ipu_csi_set_testgen_mclk() argument
198 div_ratio = (ipu_clk / pixel_clk) - 1; in ipu_csi_set_testgen_mclk()
201 dev_err(csi->ipu->dev, in ipu_csi_set_testgen_mclk()
203 return -EINVAL; in ipu_csi_set_testgen_mclk()
206 temp = ipu_csi_read(csi, CSI_SENS_CONF); in ipu_csi_set_testgen_mclk()
208 ipu_csi_write(csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT), in ipu_csi_set_testgen_mclk()
215 * Find the CSI data format and data width for the given V4L2 media
227 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565; in mbus_code_to_bus_cfg()
229 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; in mbus_code_to_bus_cfg()
230 cfg->mipi_dt = MIPI_DT_RGB565; in mbus_code_to_bus_cfg()
231 cfg->data_width = IPU_CSI_DATA_WIDTH_8; in mbus_code_to_bus_cfg()
235 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444; in mbus_code_to_bus_cfg()
236 cfg->mipi_dt = MIPI_DT_RGB444; in mbus_code_to_bus_cfg()
237 cfg->data_width = IPU_CSI_DATA_WIDTH_8; in mbus_code_to_bus_cfg()
241 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555; in mbus_code_to_bus_cfg()
242 cfg->mipi_dt = MIPI_DT_RGB555; in mbus_code_to_bus_cfg()
243 cfg->data_width = IPU_CSI_DATA_WIDTH_8; in mbus_code_to_bus_cfg()
247 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444; in mbus_code_to_bus_cfg()
248 cfg->mipi_dt = MIPI_DT_RGB888; in mbus_code_to_bus_cfg()
249 cfg->data_width = IPU_CSI_DATA_WIDTH_8; in mbus_code_to_bus_cfg()
252 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY; in mbus_code_to_bus_cfg()
253 cfg->mipi_dt = MIPI_DT_YUV422; in mbus_code_to_bus_cfg()
254 cfg->data_width = IPU_CSI_DATA_WIDTH_8; in mbus_code_to_bus_cfg()
257 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV; in mbus_code_to_bus_cfg()
258 cfg->mipi_dt = MIPI_DT_YUV422; in mbus_code_to_bus_cfg()
259 cfg->data_width = IPU_CSI_DATA_WIDTH_8; in mbus_code_to_bus_cfg()
263 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY; in mbus_code_to_bus_cfg()
264 cfg->data_width = IPU_CSI_DATA_WIDTH_8; in mbus_code_to_bus_cfg()
266 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; in mbus_code_to_bus_cfg()
267 cfg->data_width = IPU_CSI_DATA_WIDTH_16; in mbus_code_to_bus_cfg()
269 cfg->mipi_dt = MIPI_DT_YUV422; in mbus_code_to_bus_cfg()
273 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV; in mbus_code_to_bus_cfg()
274 cfg->data_width = IPU_CSI_DATA_WIDTH_8; in mbus_code_to_bus_cfg()
276 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; in mbus_code_to_bus_cfg()
277 cfg->data_width = IPU_CSI_DATA_WIDTH_16; in mbus_code_to_bus_cfg()
279 cfg->mipi_dt = MIPI_DT_YUV422; in mbus_code_to_bus_cfg()
286 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; in mbus_code_to_bus_cfg()
287 cfg->mipi_dt = MIPI_DT_RAW8; in mbus_code_to_bus_cfg()
288 cfg->data_width = IPU_CSI_DATA_WIDTH_8; in mbus_code_to_bus_cfg()
298 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; in mbus_code_to_bus_cfg()
299 cfg->mipi_dt = MIPI_DT_RAW10; in mbus_code_to_bus_cfg()
300 cfg->data_width = IPU_CSI_DATA_WIDTH_8; in mbus_code_to_bus_cfg()
307 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; in mbus_code_to_bus_cfg()
308 cfg->mipi_dt = MIPI_DT_RAW10; in mbus_code_to_bus_cfg()
309 cfg->data_width = IPU_CSI_DATA_WIDTH_10; in mbus_code_to_bus_cfg()
316 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER; in mbus_code_to_bus_cfg()
317 cfg->mipi_dt = MIPI_DT_RAW12; in mbus_code_to_bus_cfg()
318 cfg->data_width = IPU_CSI_DATA_WIDTH_12; in mbus_code_to_bus_cfg()
322 cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG; in mbus_code_to_bus_cfg()
323 cfg->mipi_dt = MIPI_DT_RAW8; in mbus_code_to_bus_cfg()
324 cfg->data_width = IPU_CSI_DATA_WIDTH_8; in mbus_code_to_bus_cfg()
327 return -EINVAL; in mbus_code_to_bus_cfg()
343 * Fill a CSI bus config struct from mbus_config and mbus_framefmt.
353 ret = mbus_code_to_bus_cfg(csicfg, mbus_fmt->code, mbus_cfg->type); in fill_csi_bus_cfg()
357 switch (mbus_cfg->type) { in fill_csi_bus_cfg()
359 csicfg->ext_vsync = 1; in fill_csi_bus_cfg()
360 csicfg->vsync_pol = (mbus_cfg->bus.parallel.flags & in fill_csi_bus_cfg()
362 csicfg->hsync_pol = (mbus_cfg->bus.parallel.flags & in fill_csi_bus_cfg()
364 csicfg->pixclk_pol = (mbus_cfg->bus.parallel.flags & in fill_csi_bus_cfg()
366 csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; in fill_csi_bus_cfg()
369 csicfg->ext_vsync = 0; in fill_csi_bus_cfg()
371 is_bt1120 = mbus_fmt->code == MEDIA_BUS_FMT_UYVY8_1X16 || in fill_csi_bus_cfg()
372 mbus_fmt->code == MEDIA_BUS_FMT_YUYV8_1X16; in fill_csi_bus_cfg()
373 if (V4L2_FIELD_HAS_BOTH(mbus_fmt->field) || in fill_csi_bus_cfg()
374 mbus_fmt->field == V4L2_FIELD_ALTERNATE) in fill_csi_bus_cfg()
375 csicfg->clk_mode = is_bt1120 ? in fill_csi_bus_cfg()
379 csicfg->clk_mode = is_bt1120 ? in fill_csi_bus_cfg()
385 * MIPI CSI-2 requires non gated clock mode, all other in fill_csi_bus_cfg()
386 * parameters are not applicable for MIPI CSI-2 bus. in fill_csi_bus_cfg()
388 csicfg->clk_mode = IPU_CSI_CLK_MODE_NONGATED_CLK; in fill_csi_bus_cfg()
399 ipu_csi_set_bt_interlaced_codes(struct ipu_csi *csi, in ipu_csi_set_bt_interlaced_codes() argument
408 infield = ipu_csi_translate_field(infmt->field, std); in ipu_csi_set_bt_interlaced_codes()
409 outfield = ipu_csi_translate_field(outfmt->field, std); in ipu_csi_set_bt_interlaced_codes()
412 * Write the H-V-F codes the CSI will match against the in ipu_csi_set_bt_interlaced_codes()
416 * is SEQ_TB), swap the F-bit so that the CSI will capture in ipu_csi_set_bt_interlaced_codes()
430 ipu_csi_write(csi, 0x40596 | CSI_CCIR_ERR_DET_EN, in ipu_csi_set_bt_interlaced_codes()
432 ipu_csi_write(csi, 0xD07DF, CSI_CCIR_CODE_2); in ipu_csi_set_bt_interlaced_codes()
434 dev_dbg(csi->ipu->dev, "capture field swap\n"); in ipu_csi_set_bt_interlaced_codes()
436 /* same as above but with F-bit inverted */ in ipu_csi_set_bt_interlaced_codes()
437 ipu_csi_write(csi, 0xD07DF | CSI_CCIR_ERR_DET_EN, in ipu_csi_set_bt_interlaced_codes()
439 ipu_csi_write(csi, 0x40596, CSI_CCIR_CODE_2); in ipu_csi_set_bt_interlaced_codes()
442 ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); in ipu_csi_set_bt_interlaced_codes()
448 int ipu_csi_init_interface(struct ipu_csi *csi, in ipu_csi_init_interface() argument
464 width = infmt->width; in ipu_csi_init_interface()
465 height = infmt->height; in ipu_csi_init_interface()
466 if (infmt->field == V4L2_FIELD_ALTERNATE) in ipu_csi_init_interface()
467 height *= 2; in ipu_csi_init_interface()
482 spin_lock_irqsave(&csi->lock, flags); in ipu_csi_init_interface()
484 ipu_csi_write(csi, data, CSI_SENS_CONF); in ipu_csi_init_interface()
490 ipu_csi_write(csi, 0x40030, CSI_CCIR_CODE_1); in ipu_csi_init_interface()
491 ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); in ipu_csi_init_interface()
501 dev_err(csi->ipu->dev, in ipu_csi_init_interface()
503 ret = -EINVAL; in ipu_csi_init_interface()
507 ret = ipu_csi_set_bt_interlaced_codes(csi, infmt, outfmt, std); in ipu_csi_init_interface()
515 ipu_csi_write(csi, 0x40030 | CSI_CCIR_ERR_DET_EN, in ipu_csi_init_interface()
517 ipu_csi_write(csi, 0xFF0000, CSI_CCIR_CODE_3); in ipu_csi_init_interface()
521 ipu_csi_write(csi, 0, CSI_CCIR_CODE_1); in ipu_csi_init_interface()
526 ipu_csi_write(csi, (width - 1) | ((height - 1) << 16), in ipu_csi_init_interface()
529 dev_dbg(csi->ipu->dev, "CSI_SENS_CONF = 0x%08X\n", in ipu_csi_init_interface()
530 ipu_csi_read(csi, CSI_SENS_CONF)); in ipu_csi_init_interface()
531 dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n", in ipu_csi_init_interface()
532 ipu_csi_read(csi, CSI_ACT_FRM_SIZE)); in ipu_csi_init_interface()
535 spin_unlock_irqrestore(&csi->lock, flags); in ipu_csi_init_interface()
541 bool ipu_csi_is_interlaced(struct ipu_csi *csi) in ipu_csi_is_interlaced() argument
546 spin_lock_irqsave(&csi->lock, flags); in ipu_csi_is_interlaced()
548 (ipu_csi_read(csi, CSI_SENS_CONF) & in ipu_csi_is_interlaced()
551 spin_unlock_irqrestore(&csi->lock, flags); in ipu_csi_is_interlaced()
565 dev_err(csi->ipu->dev, in ipu_csi_is_interlaced()
566 "CSI %d sensor protocol unsupported\n", csi->id); in ipu_csi_is_interlaced()
572 void ipu_csi_get_window(struct ipu_csi *csi, struct v4l2_rect *w) in ipu_csi_get_window() argument
577 spin_lock_irqsave(&csi->lock, flags); in ipu_csi_get_window()
579 reg = ipu_csi_read(csi, CSI_ACT_FRM_SIZE); in ipu_csi_get_window()
580 w->width = (reg & 0xFFFF) + 1; in ipu_csi_get_window()
581 w->height = (reg >> 16 & 0xFFFF) + 1; in ipu_csi_get_window()
583 reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL); in ipu_csi_get_window()
584 w->left = (reg & CSI_HSC_MASK) >> CSI_HSC_SHIFT; in ipu_csi_get_window()
585 w->top = (reg & CSI_VSC_MASK) >> CSI_VSC_SHIFT; in ipu_csi_get_window()
587 spin_unlock_irqrestore(&csi->lock, flags); in ipu_csi_get_window()
591 void ipu_csi_set_window(struct ipu_csi *csi, struct v4l2_rect *w) in ipu_csi_set_window() argument
596 spin_lock_irqsave(&csi->lock, flags); in ipu_csi_set_window()
598 ipu_csi_write(csi, (w->width - 1) | ((w->height - 1) << 16), in ipu_csi_set_window()
601 reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL); in ipu_csi_set_window()
603 reg |= ((w->top << CSI_VSC_SHIFT) | (w->left << CSI_HSC_SHIFT)); in ipu_csi_set_window()
604 ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL); in ipu_csi_set_window()
606 spin_unlock_irqrestore(&csi->lock, flags); in ipu_csi_set_window()
610 void ipu_csi_set_downsize(struct ipu_csi *csi, bool horiz, bool vert) in ipu_csi_set_downsize() argument
615 spin_lock_irqsave(&csi->lock, flags); in ipu_csi_set_downsize()
617 reg = ipu_csi_read(csi, CSI_OUT_FRM_CTRL); in ipu_csi_set_downsize()
621 ipu_csi_write(csi, reg, CSI_OUT_FRM_CTRL); in ipu_csi_set_downsize()
623 spin_unlock_irqrestore(&csi->lock, flags); in ipu_csi_set_downsize()
627 void ipu_csi_set_test_generator(struct ipu_csi *csi, bool active, in ipu_csi_set_test_generator() argument
632 u32 ipu_clk = clk_get_rate(csi->clk_ipu); in ipu_csi_set_test_generator()
635 spin_lock_irqsave(&csi->lock, flags); in ipu_csi_set_test_generator()
637 temp = ipu_csi_read(csi, CSI_TST_CTRL); in ipu_csi_set_test_generator()
641 ipu_csi_write(csi, temp, CSI_TST_CTRL); in ipu_csi_set_test_generator()
644 ipu_csi_set_testgen_mclk(csi, pix_clk, ipu_clk); in ipu_csi_set_test_generator()
652 ipu_csi_write(csi, temp, CSI_TST_CTRL); in ipu_csi_set_test_generator()
655 spin_unlock_irqrestore(&csi->lock, flags); in ipu_csi_set_test_generator()
659 int ipu_csi_set_mipi_datatype(struct ipu_csi *csi, u32 vc, in ipu_csi_set_mipi_datatype() argument
668 return -EINVAL; in ipu_csi_set_mipi_datatype()
670 ret = mbus_code_to_bus_cfg(&cfg, mbus_fmt->code, V4L2_MBUS_CSI2_DPHY); in ipu_csi_set_mipi_datatype()
674 spin_lock_irqsave(&csi->lock, flags); in ipu_csi_set_mipi_datatype()
676 temp = ipu_csi_read(csi, CSI_MIPI_DI); in ipu_csi_set_mipi_datatype()
679 ipu_csi_write(csi, temp, CSI_MIPI_DI); in ipu_csi_set_mipi_datatype()
681 spin_unlock_irqrestore(&csi->lock, flags); in ipu_csi_set_mipi_datatype()
687 int ipu_csi_set_skip_smfc(struct ipu_csi *csi, u32 skip, in ipu_csi_set_skip_smfc() argument
694 return -EINVAL; in ipu_csi_set_skip_smfc()
696 spin_lock_irqsave(&csi->lock, flags); in ipu_csi_set_skip_smfc()
698 temp = ipu_csi_read(csi, CSI_SKIP); in ipu_csi_set_skip_smfc()
704 ipu_csi_write(csi, temp, CSI_SKIP); in ipu_csi_set_skip_smfc()
706 spin_unlock_irqrestore(&csi->lock, flags); in ipu_csi_set_skip_smfc()
712 int ipu_csi_set_dest(struct ipu_csi *csi, enum ipu_csi_dest csi_dest) in ipu_csi_set_dest() argument
722 spin_lock_irqsave(&csi->lock, flags); in ipu_csi_set_dest()
724 csi_sens_conf = ipu_csi_read(csi, CSI_SENS_CONF); in ipu_csi_set_dest()
727 ipu_csi_write(csi, csi_sens_conf, CSI_SENS_CONF); in ipu_csi_set_dest()
729 spin_unlock_irqrestore(&csi->lock, flags); in ipu_csi_set_dest()
735 int ipu_csi_enable(struct ipu_csi *csi) in ipu_csi_enable() argument
737 ipu_module_enable(csi->ipu, csi->module); in ipu_csi_enable()
743 int ipu_csi_disable(struct ipu_csi *csi) in ipu_csi_disable() argument
745 ipu_module_disable(csi->ipu, csi->module); in ipu_csi_disable()
754 struct ipu_csi *csi, *ret; in ipu_csi_get() local
757 return ERR_PTR(-EINVAL); in ipu_csi_get()
759 csi = ipu->csi_priv[id]; in ipu_csi_get()
760 ret = csi; in ipu_csi_get()
762 spin_lock_irqsave(&csi->lock, flags); in ipu_csi_get()
764 if (csi->inuse) { in ipu_csi_get()
765 ret = ERR_PTR(-EBUSY); in ipu_csi_get()
769 csi->inuse = true; in ipu_csi_get()
771 spin_unlock_irqrestore(&csi->lock, flags); in ipu_csi_get()
776 void ipu_csi_put(struct ipu_csi *csi) in ipu_csi_put() argument
780 spin_lock_irqsave(&csi->lock, flags); in ipu_csi_put()
781 csi->inuse = false; in ipu_csi_put()
782 spin_unlock_irqrestore(&csi->lock, flags); in ipu_csi_put()
789 struct ipu_csi *csi; in ipu_csi_init() local
792 return -ENODEV; in ipu_csi_init()
794 csi = devm_kzalloc(dev, sizeof(*csi), GFP_KERNEL); in ipu_csi_init()
795 if (!csi) in ipu_csi_init()
796 return -ENOMEM; in ipu_csi_init()
798 ipu->csi_priv[id] = csi; in ipu_csi_init()
800 spin_lock_init(&csi->lock); in ipu_csi_init()
801 csi->module = module; in ipu_csi_init()
802 csi->id = id; in ipu_csi_init()
803 csi->clk_ipu = clk_ipu; in ipu_csi_init()
804 csi->base = devm_ioremap(dev, base, PAGE_SIZE); in ipu_csi_init()
805 if (!csi->base) in ipu_csi_init()
806 return -ENOMEM; in ipu_csi_init()
808 dev_dbg(dev, "CSI%d base: 0x%08lx remapped to %p\n", in ipu_csi_init()
809 id, base, csi->base); in ipu_csi_init()
810 csi->ipu = ipu; in ipu_csi_init()
819 void ipu_csi_dump(struct ipu_csi *csi) in ipu_csi_dump() argument
821 dev_dbg(csi->ipu->dev, "CSI_SENS_CONF: %08x\n", in ipu_csi_dump()
822 ipu_csi_read(csi, CSI_SENS_CONF)); in ipu_csi_dump()
823 dev_dbg(csi->ipu->dev, "CSI_SENS_FRM_SIZE: %08x\n", in ipu_csi_dump()
824 ipu_csi_read(csi, CSI_SENS_FRM_SIZE)); in ipu_csi_dump()
825 dev_dbg(csi->ipu->dev, "CSI_ACT_FRM_SIZE: %08x\n", in ipu_csi_dump()
826 ipu_csi_read(csi, CSI_ACT_FRM_SIZE)); in ipu_csi_dump()
827 dev_dbg(csi->ipu->dev, "CSI_OUT_FRM_CTRL: %08x\n", in ipu_csi_dump()
828 ipu_csi_read(csi, CSI_OUT_FRM_CTRL)); in ipu_csi_dump()
829 dev_dbg(csi->ipu->dev, "CSI_TST_CTRL: %08x\n", in ipu_csi_dump()
830 ipu_csi_read(csi, CSI_TST_CTRL)); in ipu_csi_dump()
831 dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_1: %08x\n", in ipu_csi_dump()
832 ipu_csi_read(csi, CSI_CCIR_CODE_1)); in ipu_csi_dump()
833 dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_2: %08x\n", in ipu_csi_dump()
834 ipu_csi_read(csi, CSI_CCIR_CODE_2)); in ipu_csi_dump()
835 dev_dbg(csi->ipu->dev, "CSI_CCIR_CODE_3: %08x\n", in ipu_csi_dump()
836 ipu_csi_read(csi, CSI_CCIR_CODE_3)); in ipu_csi_dump()
837 dev_dbg(csi->ipu->dev, "CSI_MIPI_DI: %08x\n", in ipu_csi_dump()
838 ipu_csi_read(csi, CSI_MIPI_DI)); in ipu_csi_dump()
839 dev_dbg(csi->ipu->dev, "CSI_SKIP: %08x\n", in ipu_csi_dump()
840 ipu_csi_read(csi, CSI_SKIP)); in ipu_csi_dump()