}
switch (group->slot) {
+ case GROUP_SLOT_PAF:
+ fimc_is_hw_group_init(group);
+ group->subdev[ENTRY_PAF] = &device->group_paf.leader;
+
+ list_add_tail(&device->group_paf.leader.list, &group->subdev_list);
+ break;
case GROUP_SLOT_3AA:
fimc_is_hw_group_init(group);
group->subdev[ENTRY_3AA] = &device->group_3aa.leader;
case GROUP_ID_SS4:
case GROUP_ID_SS5:
#endif
+ case GROUP_ID_PAF0:
+ case GROUP_ID_PAF1:
case GROUP_ID_3AA0:
case GROUP_ID_3AA1:
case GROUP_ID_ISP0:
return IRQ_HANDLED;
}
+static irqreturn_t fimc_is_isr1_paf0(int irq, void *data)
+{
+ fimc_is_isr1_host(data);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fimc_is_isr1_paf1(int irq, void *data)
+{
+ fimc_is_isr1_host(data);
+ return IRQ_HANDLED;
+}
+
inline int fimc_is_hw_slot_id(int hw_id)
{
int slot_id = -1;
case DEV_HW_VRA:
slot_id = 4;
break;
+ case DEV_HW_PAF0:
+ slot_id = 5;
+ break;
+ case DEV_HW_PAF1:
+ slot_id = 6;
+ break;
default:
break;
}
hw_list[i] = -1;
switch (group_id) {
+ case GROUP_ID_PAF0:
+ hw_list[hw_index] = DEV_HW_PAF0; hw_index++;
+ break;
+ case GROUP_ID_PAF1:
+ hw_list[hw_index] = DEV_HW_PAF1; hw_index++;
+ break;
case GROUP_ID_3AA0:
hw_list[hw_index] = DEV_HW_3AA0; hw_index++;
break;
spin_lock_init(&clk_gate->slock);
break;
+ case DEV_HW_PAF0:
+ case DEV_HW_PAF1:
+ break;
default:
probe_err("hw_id(%d) is invalid", hw_id);
ret = -EINVAL;
info_itfc("[ID:%2d] VRA1 VA(0x%p)\n", hw_id, itf_hwip->hw_ip->regs_b);
break;
+ case DEV_HW_PAF0:
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, IORESOURCE_PAF_RDMA);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Failed to get io memory region\n");
+ return -EINVAL;
+ }
+
+ itf_hwip->hw_ip->regs_start = mem_res->start;
+ itf_hwip->hw_ip->regs_end = mem_res->end;
+ itf_hwip->hw_ip->regs = ioremap_nocache(mem_res->start, resource_size(mem_res));
+ if (!itf_hwip->hw_ip->regs) {
+ dev_err(&pdev->dev, "Failed to remap io region\n");
+ return -EINVAL;
+ }
+
+ info_itfc("[ID:%2d] PAF0 RD VA(0x%p)\n", hw_id, itf_hwip->hw_ip->regs);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, IORESOURCE_PAF_CORE);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Failed to get io memory region\n");
+ return -EINVAL;
+ }
+
+ itf_hwip->hw_ip->regs_b_start = mem_res->start;
+ itf_hwip->hw_ip->regs_b_end = mem_res->end;
+ itf_hwip->hw_ip->regs_b = ioremap_nocache(mem_res->start, resource_size(mem_res));
+ if (!itf_hwip->hw_ip->regs_b) {
+ dev_err(&pdev->dev, "Failed to remap io region\n");
+ return -EINVAL;
+ }
+
+ info_itfc("[ID:%2d] PAF0 COMMON VA(0x%p)\n", hw_id, itf_hwip->hw_ip->regs_b);
+ break;
+ case DEV_HW_PAF1:
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, IORESOURCE_PAF_RDMA);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Failed to get io memory region\n");
+ return -EINVAL;
+ }
+
+ itf_hwip->hw_ip->regs_start = mem_res->start;
+ itf_hwip->hw_ip->regs_end = mem_res->end;
+ itf_hwip->hw_ip->regs = ioremap_nocache(mem_res->start, resource_size(mem_res));
+ if (!itf_hwip->hw_ip->regs) {
+ dev_err(&pdev->dev, "Failed to remap io region\n");
+ return -EINVAL;
+ }
+
+ info_itfc("[ID:%2d] PAF1 RD VA(0x%p)\n", hw_id, itf_hwip->hw_ip->regs);
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, IORESOURCE_PAF_CORE);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Failed to get io memory region\n");
+ return -EINVAL;
+ }
+
+ itf_hwip->hw_ip->regs_b_start = mem_res->start;
+ itf_hwip->hw_ip->regs_b_end = mem_res->end;
+ itf_hwip->hw_ip->regs_b = ioremap_nocache(mem_res->start, resource_size(mem_res));
+ if (!itf_hwip->hw_ip->regs_b) {
+ dev_err(&pdev->dev, "Failed to remap io region\n");
+ return -EINVAL;
+ }
+
+ info_itfc("[ID:%2d] PAF1 COMMON VA(0x%p)\n", hw_id, itf_hwip->hw_ip->regs_b);
+ break;
default:
probe_err("hw_id(%d) is invalid", hw_id);
return -EINVAL;
return -EINVAL;
}
break;
+ case DEV_HW_PAF0:
+ itf_hwip->irq[INTR_HWIP1] = platform_get_irq(pdev, 8);
+ if (itf_hwip->irq[INTR_HWIP1] < 0) {
+ err("Failed to get irq PAF0\n");
+ return -EINVAL;
+ }
+ break;
+ case DEV_HW_PAF1:
+ itf_hwip->irq[INTR_HWIP1] = platform_get_irq(pdev, 9);
+ if (itf_hwip->irq[INTR_HWIP1] < 0) {
+ err("Failed to get irq PAF1\n");
+ return -EINVAL;
+ }
+ break;
default:
probe_err("hw_id(%d) is invalid", hw_id);
return -EINVAL;
case DEV_HW_VRA:
ret = __fimc_is_hw_request_irq(itf_hwip, "vra", INTR_HWIP2, fimc_is_isr1_vra); /* VRA CH1 */
break;
+ case DEV_HW_PAF0:
+ ret = __fimc_is_hw_request_irq(itf_hwip, "paf0", INTR_HWIP1, fimc_is_isr1_paf0);
+ break;
+ case DEV_HW_PAF1:
+ ret = __fimc_is_hw_request_irq(itf_hwip, "paf1", INTR_HWIP1, fimc_is_isr1_paf1);
+ break;
default:
probe_err("hw_id(%d) is invalid", hw_id);
return -EINVAL;
--- /dev/null
+/*
+ * Samsung Exynos5 SoC series FIMC-IS driver
+ *
+ * exynos5 fimc-is video functions
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd
+ *
+ * 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.
+ */
+
+#include "fimc-is-device-ischain.h"
+#include "fimc-is-device-sensor.h"
+#include "fimc-is-subdev-ctrl.h"
+#include "fimc-is-config.h"
+#include "fimc-is-param.h"
+#include "fimc-is-video.h"
+#include "fimc-is-type.h"
+
+static int fimc_is_ischain_paf_cfg(struct fimc_is_subdev *leader,
+ void *device_data,
+ struct fimc_is_frame *frame,
+ struct fimc_is_crop *incrop,
+ struct fimc_is_crop *otcrop,
+ u32 *lindex,
+ u32 *hindex,
+ u32 *indexes)
+{
+ int ret = 0;
+ struct fimc_is_group *group;
+ struct fimc_is_queue *queue;
+ struct param_otf_output *otf_output;
+ struct param_dma_input *dma_input;
+ struct param_control *control;
+ struct fimc_is_module_enum *module;
+ struct fimc_is_device_ischain *device;
+ u32 hw_format = DMA_INPUT_FORMAT_BAYER;
+ u32 hw_bitwidth = DMA_INPUT_BIT_WIDTH_16BIT;
+
+ device = (struct fimc_is_device_ischain *)device_data;
+
+ FIMC_BUG(!leader);
+ FIMC_BUG(!device);
+ FIMC_BUG(!device->sensor);
+ FIMC_BUG(!incrop);
+ FIMC_BUG(!lindex);
+ FIMC_BUG(!hindex);
+ FIMC_BUG(!indexes);
+
+ group = &device->group_paf;
+
+ ret = fimc_is_sensor_g_module(device->sensor, &module);
+ if (ret) {
+ merr("fimc_is_sensor_g_module is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ if (!test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state)) {
+ queue = GET_SUBDEV_QUEUE(leader);
+ if (!queue) {
+ merr("queue is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ if (!queue->framecfg.format) {
+ merr("format is NULL", device);
+ ret = -EINVAL;
+ goto p_err;
+ }
+
+ hw_format = queue->framecfg.format->hw_format;
+ hw_bitwidth = queue->framecfg.format->hw_bitwidth; /* memory width per pixel */
+ }
+
+ /* Configure Conrtol */
+ if (!frame) {
+ control = fimc_is_itf_g_param(device, NULL, PARAM_PAF_CONTROL);
+ if (test_bit(FIMC_IS_GROUP_START, &group->state)) {
+ control->cmd = CONTROL_COMMAND_START;
+ control->bypass = CONTROL_BYPASS_DISABLE;
+ } else {
+ control->cmd = CONTROL_COMMAND_STOP;
+ control->bypass = CONTROL_BYPASS_DISABLE;
+ }
+ *lindex |= LOWBIT_OF(PARAM_PAF_CONTROL);
+ *hindex |= HIGHBIT_OF(PARAM_PAF_CONTROL);
+ (*indexes)++;
+ }
+
+ dma_input = fimc_is_itf_g_param(device, frame, PARAM_PAF_DMA_INPUT);
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state))
+ dma_input->cmd = DMA_INPUT_COMMAND_DISABLE;
+ else
+ dma_input->cmd = DMA_INPUT_COMMAND_ENABLE;
+ dma_input->format = hw_format;
+ dma_input->bitwidth = hw_bitwidth;
+ dma_input->msb = module->bitwidth - 1; /* msb zero padding by HW constraint */
+ dma_input->order = DMA_INPUT_ORDER_GR_BG;
+ dma_input->plane = 1;
+ dma_input->width = incrop->w;
+ dma_input->height = incrop->h;
+
+ dma_input->dma_crop_offset = 0;
+ dma_input->dma_crop_width = leader->input.width;
+ dma_input->dma_crop_height = leader->input.height;
+ dma_input->bayer_crop_offset_x = incrop->x;
+ dma_input->bayer_crop_offset_y = incrop->y;
+ dma_input->bayer_crop_width = incrop->w;
+ dma_input->bayer_crop_height = incrop->h;
+ *lindex |= LOWBIT_OF(PARAM_PAF_DMA_INPUT);
+ *hindex |= HIGHBIT_OF(PARAM_PAF_DMA_INPUT);
+ (*indexes)++;
+
+ otf_output = fimc_is_itf_g_param(device, frame, PARAM_PAF_OTF_OUTPUT);
+ if (test_bit(FIMC_IS_GROUP_OTF_OUTPUT, &group->state))
+ otf_output->cmd = OTF_OUTPUT_COMMAND_ENABLE;
+ else
+ otf_output->cmd = OTF_OUTPUT_COMMAND_DISABLE;
+
+ otf_output->width = otcrop->w;
+ otf_output->height = otcrop->h;
+ otf_output->crop_enable = 0;
+ otf_output->format = OTF_OUTPUT_FORMAT_BAYER;
+ otf_output->bitwidth = OTF_OUTPUT_BIT_WIDTH_12BIT;
+ otf_output->order = OTF_OUTPUT_ORDER_BAYER_GR_BG;
+ *lindex |= LOWBIT_OF(PARAM_PAF_OTF_OUTPUT);
+ *hindex |= HIGHBIT_OF(PARAM_PAF_OTF_OUTPUT);
+ (*indexes)++;
+
+ leader->input.crop = *incrop;
+
+p_err:
+ return ret;
+}
+
+static int fimc_is_ischain_paf_tag(struct fimc_is_subdev *subdev,
+ void *device_data,
+ struct fimc_is_frame *frame,
+ struct camera2_node *node)
+{
+ int ret = 0;
+ struct fimc_is_group *group;
+ struct paf_rdma_param *paf_param;
+ struct fimc_is_crop inparm, otparm;
+ struct fimc_is_crop *incrop, *otcrop;
+ struct fimc_is_subdev *leader;
+ struct fimc_is_device_ischain *device;
+ u32 lindex, hindex, indexes;
+
+ device = (struct fimc_is_device_ischain *)device_data;
+
+ FIMC_BUG(!subdev);
+ FIMC_BUG(!device);
+ FIMC_BUG(!device->is_region);
+ FIMC_BUG(!frame);
+
+ mdbgs_ischain(4, "PAF TAG\n", device);
+
+ incrop = (struct fimc_is_crop *)node->input.cropRegion;
+ otcrop = (struct fimc_is_crop *)node->output.cropRegion;
+
+ group = &device->group_paf;
+ leader = subdev->leader;
+ lindex = hindex = indexes = 0;
+ paf_param = &device->is_region->parameter.paf;
+
+ if (test_bit(FIMC_IS_GROUP_OTF_INPUT, &group->state)) {
+ merr("%s is fail: paf rdma is not supported OTF_INPUT", device, __func__);
+ goto p_err;
+ } else {
+ inparm.x = 0;
+ inparm.y = 0;
+ inparm.w = paf_param->dma_input.dma_crop_width;
+ inparm.h = paf_param->dma_input.dma_crop_height;
+ }
+
+ if (IS_NULL_CROP(incrop))
+ *incrop = inparm;
+
+ /* not supported DMA input crop */
+ if ((incrop->x != 0) || (incrop->y != 0))
+ *incrop = inparm;
+
+ if (test_bit(FIMC_IS_GROUP_OTF_OUTPUT, &group->state)) {
+ otparm.x = 0;
+ otparm.y = 0;
+ otparm.w = paf_param->otf_output.width;
+ otparm.h = paf_param->otf_output.height;
+ } else {
+ otparm.x = otcrop->x;
+ otparm.y = otcrop->y;
+ otparm.w = otcrop->w;
+ otparm.h = otcrop->h;
+ }
+
+ if (IS_NULL_CROP(otcrop)) {
+ msrwarn("ot_crop [%d, %d, %d, %d] -> [%d, %d, %d, %d]\n", device, subdev, frame,
+ otcrop->x, otcrop->y, otcrop->w, otcrop->h,
+ otparm.x, otparm.y, otparm.w, otparm.h);
+ *otcrop = otparm;
+ }
+ set_bit(FIMC_IS_SUBDEV_FORCE_SET, &leader->state);
+
+ if (!COMPARE_CROP(incrop, &inparm) ||
+ !COMPARE_CROP(otcrop, &otparm) ||
+ test_bit(FIMC_IS_SUBDEV_FORCE_SET, &leader->state)) {
+ ret = fimc_is_ischain_paf_cfg(subdev,
+ device,
+ frame,
+ incrop,
+ otcrop,
+ &lindex,
+ &hindex,
+ &indexes);
+ if (ret) {
+ merr("fimc_is_ischain_paf_cfg is fail(%d)", device, ret);
+ goto p_err;
+ }
+
+ msrinfo("in_crop[%d, %d, %d, %d]\n", device, subdev, frame,
+ incrop->x, incrop->y, incrop->w, incrop->h);
+ msrinfo("ot_crop[%d, %d, %d, %d]\n", device, subdev, frame,
+ otcrop->x, otcrop->y, otcrop->w, otcrop->h);
+ }
+
+ ret = fimc_is_itf_s_param(device, frame, lindex, hindex, indexes);
+ if (ret) {
+ mrerr("fimc_is_itf_s_param is fail(%d)", device, frame, ret);
+ goto p_err;
+ }
+
+p_err:
+ return ret;
+}
+
+const struct fimc_is_subdev_ops fimc_is_subdev_paf_ops = {
+ .bypass = NULL,
+ .cfg = fimc_is_ischain_paf_cfg,
+ .tag = fimc_is_ischain_paf_tag,
+};