Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] exynos4-is: Add Exynos5250 SoC support to fimc-lite driver

This patch adds support for the Exynos5250 SoC variant of the FIMC-LITE
IP. A 'compatible' string is added for Exynos5250 compatible devices
and the capture DMA handling is reworked to use the FLITE_REG_CIFCNTSEQ
register, masking output DMA buffer address slots. The frame interrupt
is enabled so there are now 2 interrupts per frame. This likely can be
optimized in future by using any status registers that allow to figure
out what the last and the currently written frame buffer is. It would
also be more reliable in cases where there are high interrupt service
latencies.

Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
Signed-off-by: Arun Kumar K <arun.kk@samsung.com>
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Sylwester Nawrocki and committed by
Mauro Carvalho Chehab
086eca29 47d1f33f

+125 -16
+4 -2
Documentation/devicetree/bindings/media/exynos-fimc-lite.txt
··· 2 2 3 3 Required properties: 4 4 5 - - compatible : should be "samsung,exynos4212-fimc-lite" for Exynos4212 and 6 - Exynos4412 SoCs; 5 + - compatible : should be one of: 6 + "samsung,exynos4212-fimc-lite" for Exynos4212/4412 SoCs, 7 + "samsung,exynos5250-fimc-lite" for Exynos5250 compatible 8 + devices; 7 9 - reg : physical base address and size of the device memory mapped 8 10 registers; 9 11 - interrupts : should contain FIMC-LITE interrupt;
+50 -3
drivers/media/platform/exynos4-is/fimc-lite-reg.c
··· 2 2 * Register interface file for EXYNOS FIMC-LITE (camera interface) driver 3 3 * 4 4 * Copyright (C) 2012 Samsung Electronics Co., Ltd. 5 - * Sylwester Nawrocki <s.nawrocki@samsung.com> 5 + * Author: Sylwester Nawrocki <s.nawrocki@samsung.com> 6 6 * 7 7 * This program is free software; you can redistribute it and/or modify 8 8 * it under the terms of the GNU General Public License version 2 as 9 9 * published by the Free Software Foundation. 10 10 */ 11 11 12 - #include <linux/io.h> 12 + #include <linux/bitops.h> 13 13 #include <linux/delay.h> 14 + #include <linux/io.h> 14 15 #include <media/s5p_fimc.h> 15 16 16 17 #include "fimc-lite-reg.h" ··· 69 68 if (atomic_read(&dev->out_path) == FIMC_IO_DMA) { 70 69 intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN | 71 70 FLITE_REG_CIGCTRL_IRQ_LASTEN | 72 - FLITE_REG_CIGCTRL_IRQ_STARTEN; 71 + FLITE_REG_CIGCTRL_IRQ_STARTEN | 72 + FLITE_REG_CIGCTRL_IRQ_ENDEN; 73 73 } else { 74 74 /* An output to the FIMC-IS */ 75 75 intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN | ··· 217 215 flite_hw_set_camera_port(dev, si->mux_id); 218 216 } 219 217 218 + static void flite_hw_set_pack12(struct fimc_lite *dev, int on) 219 + { 220 + u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT); 221 + 222 + cfg &= ~FLITE_REG_CIODMAFMT_PACK12; 223 + 224 + if (on) 225 + cfg |= FLITE_REG_CIODMAFMT_PACK12; 226 + 227 + writel(cfg, dev->regs + FLITE_REG_CIODMAFMT); 228 + } 229 + 220 230 static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f) 221 231 { 222 232 static const u32 pixcode[4][2] = { ··· 264 250 writel(cfg, dev->regs + FLITE_REG_CIOOFF); 265 251 } 266 252 253 + void flite_hw_set_dma_buffer(struct fimc_lite *dev, struct flite_buffer *buf) 254 + { 255 + unsigned int index; 256 + u32 cfg; 257 + 258 + if (dev->dd->max_dma_bufs == 1) 259 + index = 0; 260 + else 261 + index = buf->index; 262 + 263 + if (index == 0) 264 + writel(buf->paddr, dev->regs + FLITE_REG_CIOSA); 265 + else 266 + writel(buf->paddr, dev->regs + FLITE_REG_CIOSAN(index - 1)); 267 + 268 + cfg = readl(dev->regs + FLITE_REG_CIFCNTSEQ); 269 + cfg |= BIT(index); 270 + writel(cfg, dev->regs + FLITE_REG_CIFCNTSEQ); 271 + } 272 + 273 + void flite_hw_mask_dma_buffer(struct fimc_lite *dev, u32 index) 274 + { 275 + u32 cfg; 276 + 277 + if (dev->dd->max_dma_bufs == 1) 278 + index = 0; 279 + 280 + cfg = readl(dev->regs + FLITE_REG_CIFCNTSEQ); 281 + cfg &= ~BIT(index); 282 + writel(cfg, dev->regs + FLITE_REG_CIFCNTSEQ); 283 + } 284 + 267 285 /* Enable/disable output DMA, set output pixel size and offsets (composition) */ 268 286 void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f, 269 287 bool enable) ··· 313 267 314 268 flite_hw_set_out_order(dev, f); 315 269 flite_hw_set_dma_window(dev, f); 270 + flite_hw_set_pack12(dev, 0); 316 271 } 317 272 318 273 void flite_hw_dump_regs(struct fimc_lite *dev, const char *label)
+8 -2
drivers/media/platform/exynos4-is/fimc-lite-reg.h
··· 120 120 /* b0: 1 - camera B, 0 - camera A */ 121 121 #define FLITE_REG_CIGENERAL_CAM_B (1 << 0) 122 122 123 + #define FLITE_REG_CIFCNTSEQ 0x100 124 + #define FLITE_REG_CIOSAN(x) (0x200 + (4 * (x))) 125 + 123 126 /* ---------------------------------------------------------------------------- 124 127 * Function declarations 125 128 */ ··· 145 142 void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f); 146 143 void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on); 147 144 void flite_hw_dump_regs(struct fimc_lite *dev, const char *label); 145 + void flite_hw_set_dma_buffer(struct fimc_lite *dev, struct flite_buffer *buf); 146 + void flite_hw_mask_dma_buffer(struct fimc_lite *dev, u32 index); 148 147 149 - static inline void flite_hw_set_output_addr(struct fimc_lite *dev, u32 paddr) 148 + static inline void flite_hw_set_dma_buf_mask(struct fimc_lite *dev, u32 mask) 150 149 { 151 - writel(paddr, dev->regs + FLITE_REG_CIOSA); 150 + writel(mask, dev->regs + FLITE_REG_CIFCNTSEQ); 152 151 } 152 + 153 153 #endif /* FIMC_LITE_REG_H */
+43 -7
drivers/media/platform/exynos4-is/fimc-lite.c
··· 153 153 flite_hw_set_camera_bus(fimc, si); 154 154 flite_hw_set_source_format(fimc, &fimc->inp_frame); 155 155 flite_hw_set_window_offset(fimc, &fimc->inp_frame); 156 + flite_hw_set_dma_buf_mask(fimc, 0); 156 157 flite_hw_set_output_dma(fimc, &fimc->out_frame, !isp_output); 157 158 flite_hw_set_interrupt_mask(fimc); 158 159 flite_hw_set_test_pattern(fimc, fimc->test_pattern->val); ··· 277 276 278 277 if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) && 279 278 test_bit(ST_FLITE_RUN, &fimc->state) && 280 - !list_empty(&fimc->active_buf_q) && 281 279 !list_empty(&fimc->pending_buf_q)) { 280 + vbuf = fimc_lite_pending_queue_pop(fimc); 281 + flite_hw_set_dma_buffer(fimc, vbuf); 282 + fimc_lite_active_queue_add(fimc, vbuf); 283 + } 284 + 285 + if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMEND) && 286 + test_bit(ST_FLITE_RUN, &fimc->state) && 287 + !list_empty(&fimc->active_buf_q)) { 282 288 vbuf = fimc_lite_active_queue_pop(fimc); 283 289 ktime_get_ts(&ts); 284 290 tv = &vbuf->vb.v4l2_buf.timestamp; 285 291 tv->tv_sec = ts.tv_sec; 286 292 tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; 287 293 vbuf->vb.v4l2_buf.sequence = fimc->frame_count++; 294 + flite_hw_mask_dma_buffer(fimc, vbuf->index); 288 295 vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE); 289 - 290 - vbuf = fimc_lite_pending_queue_pop(fimc); 291 - flite_hw_set_output_addr(fimc, vbuf->paddr); 292 - fimc_lite_active_queue_add(fimc, vbuf); 293 296 } 294 297 295 298 if (test_bit(ST_FLITE_CONFIG, &fimc->state)) ··· 312 307 static int start_streaming(struct vb2_queue *q, unsigned int count) 313 308 { 314 309 struct fimc_lite *fimc = q->drv_priv; 310 + unsigned long flags; 315 311 int ret; 316 312 313 + spin_lock_irqsave(&fimc->slock, flags); 314 + 315 + fimc->buf_index = 0; 317 316 fimc->frame_count = 0; 317 + 318 + spin_unlock_irqrestore(&fimc->slock, flags); 318 319 319 320 ret = fimc_lite_hw_init(fimc, false); 320 321 if (ret) { ··· 423 412 spin_lock_irqsave(&fimc->slock, flags); 424 413 buf->paddr = vb2_dma_contig_plane_dma_addr(vb, 0); 425 414 415 + buf->index = fimc->buf_index++; 416 + if (fimc->buf_index >= fimc->reqbufs_count) 417 + fimc->buf_index = 0; 418 + 426 419 if (!test_bit(ST_FLITE_SUSPENDED, &fimc->state) && 427 420 !test_bit(ST_FLITE_STREAM, &fimc->state) && 428 421 list_empty(&fimc->active_buf_q)) { 429 - flite_hw_set_output_addr(fimc, buf->paddr); 422 + flite_hw_set_dma_buffer(fimc, buf); 430 423 fimc_lite_active_queue_add(fimc, buf); 431 424 } else { 432 425 fimc_lite_pending_queue_add(fimc, buf); ··· 1466 1451 fimc->index = of_alias_get_id(dev->of_node, "fimc-lite"); 1467 1452 } 1468 1453 1469 - if (!drv_data || fimc->index < 0 || fimc->index >= FIMC_LITE_MAX_DEVS) 1454 + if (!drv_data || fimc->index >= drv_data->num_instances || 1455 + fimc->index < 0) { 1456 + dev_err(dev, "Wrong %s node alias\n", 1457 + dev->of_node->full_name); 1470 1458 return -EINVAL; 1459 + } 1471 1460 1472 1461 fimc->dd = drv_data; 1473 1462 fimc->pdev = pdev; ··· 1628 1609 .out_width_align = 8, 1629 1610 .win_hor_offs_align = 2, 1630 1611 .out_hor_offs_align = 8, 1612 + .max_dma_bufs = 1, 1613 + .num_instances = 2, 1614 + }; 1615 + 1616 + /* EXYNOS5250 */ 1617 + static struct flite_drvdata fimc_lite_drvdata_exynos5 = { 1618 + .max_width = 8192, 1619 + .max_height = 8192, 1620 + .out_width_align = 8, 1621 + .win_hor_offs_align = 2, 1622 + .out_hor_offs_align = 8, 1623 + .max_dma_bufs = 32, 1624 + .num_instances = 3, 1631 1625 }; 1632 1626 1633 1627 static const struct of_device_id flite_of_match[] = { 1634 1628 { 1635 1629 .compatible = "samsung,exynos4212-fimc-lite", 1636 1630 .data = &fimc_lite_drvdata_exynos4, 1631 + }, 1632 + { 1633 + .compatible = "samsung,exynos5250-fimc-lite", 1634 + .data = &fimc_lite_drvdata_exynos5, 1637 1635 }, 1638 1636 { /* sentinel */ }, 1639 1637 };
+20 -2
drivers/media/platform/exynos4-is/fimc-lite.h
··· 27 27 28 28 #define FIMC_LITE_DRV_NAME "exynos-fimc-lite" 29 29 #define FLITE_CLK_NAME "flite" 30 - #define FIMC_LITE_MAX_DEVS 2 30 + #define FIMC_LITE_MAX_DEVS 3 31 31 #define FLITE_REQ_BUFS_MIN 2 32 32 33 33 /* Bit index definitions for struct fimc_lite::state */ ··· 48 48 #define FLITE_SD_PAD_SOURCE_ISP 2 49 49 #define FLITE_SD_PADS_NUM 3 50 50 51 + /** 52 + * struct flite_drvdata - FIMC-LITE IP variant data structure 53 + * @max_width: maximum camera interface input width in pixels 54 + * @max_height: maximum camera interface input height in pixels 55 + * @out_width_align: minimum output width alignment in pixels 56 + * @win_hor_offs_align: minimum camera interface crop window horizontal 57 + * offset alignment in pixels 58 + * @out_hor_offs_align: minimum output DMA compose rectangle horizontal 59 + * offset alignment in pixels 60 + * @max_dma_bufs: number of output DMA buffer start address registers 61 + * @num_instances: total number of FIMC-LITE IP instances available 62 + */ 51 63 struct flite_drvdata { 52 64 unsigned short max_width; 53 65 unsigned short max_height; 54 66 unsigned short out_width_align; 55 67 unsigned short win_hor_offs_align; 56 68 unsigned short out_hor_offs_align; 69 + unsigned short max_dma_bufs; 70 + unsigned short num_instances; 57 71 }; 58 72 59 73 struct fimc_lite_events { ··· 94 80 * struct flite_buffer - video buffer structure 95 81 * @vb: vb2 buffer 96 82 * @list: list head for the buffers queue 97 - * @paddr: precalculated physical address 83 + * @paddr: DMA buffer start address 84 + * @index: DMA start address register's index 98 85 */ 99 86 struct flite_buffer { 100 87 struct vb2_buffer vb; 101 88 struct list_head list; 102 89 dma_addr_t paddr; 90 + unsigned short index; 103 91 }; 104 92 105 93 /** ··· 135 119 * @pending_buf_q: pending buffers queue head 136 120 * @active_buf_q: the queue head of buffers scheduled in hardware 137 121 * @vb_queue: vb2 buffers queue 122 + * @buf_index: helps to keep track of the DMA start address register index 138 123 * @active_buf_count: number of video buffers scheduled in hardware 139 124 * @frame_count: the captured frames counter 140 125 * @reqbufs_count: the number of buffers requested with REQBUFS ioctl ··· 172 155 struct list_head pending_buf_q; 173 156 struct list_head active_buf_q; 174 157 struct vb2_queue vb_queue; 158 + unsigned short buf_index; 175 159 unsigned int frame_count; 176 160 unsigned int reqbufs_count; 177 161