diff options
Diffstat (limited to 'drivers/staging/media/atomisp/pci')
17 files changed, 284 insertions, 558 deletions
diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp_cmd.c index d8c7e7367386..47f18ac5e40e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.c @@ -280,14 +280,14 @@ int atomisp_freq_scaling(struct atomisp_device *isp, done: dev_dbg(isp->dev, "DFS target frequency=%d.\n", new_freq); - if ((new_freq == isp->sw_contex.running_freq) && !force) + if ((new_freq == isp->running_freq) && !force) return 0; dev_dbg(isp->dev, "Programming DFS frequency to %d\n", new_freq); ret = write_target_freq_to_hw(isp, new_freq); if (!ret) { - isp->sw_contex.running_freq = new_freq; + isp->running_freq = new_freq; trace_ipu_pstate(new_freq, -1); } return ret; @@ -679,7 +679,8 @@ void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state vb2_buffer_done(&frame->vb.vb2_buf, state); } -void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames) +void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, enum vb2_buffer_state state, + bool warn_on_css_frames) { struct ia_css_frame *frame, *_frame; unsigned long irqflags; @@ -689,15 +690,15 @@ void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_ list_for_each_entry_safe(frame, _frame, &pipe->buffers_in_css, queue) { if (warn_on_css_frames) dev_warn(pipe->isp->dev, "Warning: CSS frames queued on flush\n"); - atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR); + atomisp_buffer_done(frame, state); } list_for_each_entry_safe(frame, _frame, &pipe->activeq, queue) - atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR); + atomisp_buffer_done(frame, state); list_for_each_entry_safe(frame, _frame, &pipe->buffers_waiting_for_param, queue) { pipe->frame_request_config_id[frame->vb.vb2_buf.index] = 0; - atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR); + atomisp_buffer_done(frame, state); } spin_unlock_irqrestore(&pipe->irq_lock, irqflags); @@ -706,10 +707,10 @@ void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_ /* Returns queued buffers back to video-core */ void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd) { - atomisp_flush_video_pipe(&asd->video_out_capture, false); - atomisp_flush_video_pipe(&asd->video_out_vf, false); - atomisp_flush_video_pipe(&asd->video_out_preview, false); - atomisp_flush_video_pipe(&asd->video_out_video_capture, false); + atomisp_flush_video_pipe(&asd->video_out_capture, VB2_BUF_STATE_ERROR, false); + atomisp_flush_video_pipe(&asd->video_out_vf, VB2_BUF_STATE_ERROR, false); + atomisp_flush_video_pipe(&asd->video_out_preview, VB2_BUF_STATE_ERROR, false); + atomisp_flush_video_pipe(&asd->video_out_video_capture, VB2_BUF_STATE_ERROR, false); } /* clean out the parameters that did not apply */ @@ -4211,25 +4212,6 @@ int atomisp_digital_zoom(struct atomisp_sub_device *asd, int flag, return 0; } -/* - * Function to get sensor specific info for current resolution, - * which will be used for auto exposure conversion. - */ -int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd, - struct atomisp_sensor_mode_data *config) -{ - struct camera_mipi_info *mipi_info; - struct atomisp_device *isp = asd->isp; - - mipi_info = atomisp_to_sensor_mipi_info( - isp->inputs[asd->input_curr].camera); - if (!mipi_info) - return -EINVAL; - - memcpy(config, &mipi_info->data, sizeof(*config)); - return 0; -} - static void __atomisp_update_stream_env(struct atomisp_sub_device *asd, u16 stream_index, struct atomisp_input_stream_info *stream_info) { @@ -5010,7 +4992,6 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) struct v4l2_subdev_format vformat = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; - struct v4l2_mbus_framefmt *ffmt = &vformat.format; struct v4l2_rect isp_sink_crop; u16 source_pad = atomisp_subdev_source_pad(vdev); struct v4l2_subdev_fh fh; @@ -5049,17 +5030,17 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) /* Ensure that the resolution is equal or below the maximum supported */ vformat.which = V4L2_SUBDEV_FORMAT_ACTIVE; - v4l2_fill_mbus_format(ffmt, &f->fmt.pix, format_bridge->mbus_code); - ffmt->height += padding_h; - ffmt->width += padding_w; + v4l2_fill_mbus_format(&vformat.format, &f->fmt.pix, format_bridge->mbus_code); + vformat.format.height += padding_h; + vformat.format.width += padding_w; ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, pad, set_fmt, NULL, &vformat); if (ret) return ret; - f->fmt.pix.width = ffmt->width - padding_w; - f->fmt.pix.height = ffmt->height - padding_h; + f->fmt.pix.width = vformat.format.width - padding_w; + f->fmt.pix.height = vformat.format.height - padding_h; snr_fmt = f->fmt.pix; backup_fmt = snr_fmt; @@ -5182,9 +5163,6 @@ int atomisp_set_fmt(struct video_device *vdev, struct v4l2_format *f) if (!atomisp_subdev_format_conversion(asd, source_pad)) { padding_w = 0; padding_h = 0; - } else if (IS_BYT) { - padding_w = 12; - padding_h = 12; } /* construct resolution supported by isp */ @@ -5492,42 +5470,6 @@ out: return ret; } -int atomisp_exif_makernote(struct atomisp_sub_device *asd, - struct atomisp_makernote_info *config) -{ - struct v4l2_control ctrl; - struct atomisp_device *isp = asd->isp; - - ctrl.id = V4L2_CID_FOCAL_ABSOLUTE; - if (v4l2_g_ctrl - (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) { - dev_warn(isp->dev, "failed to g_ctrl for focal length\n"); - return -EINVAL; - } else { - config->focal_length = ctrl.value; - } - - ctrl.id = V4L2_CID_FNUMBER_ABSOLUTE; - if (v4l2_g_ctrl - (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) { - dev_warn(isp->dev, "failed to g_ctrl for f-number\n"); - return -EINVAL; - } else { - config->f_number_curr = ctrl.value; - } - - ctrl.id = V4L2_CID_FNUMBER_RANGE; - if (v4l2_g_ctrl - (isp->inputs[asd->input_curr].camera->ctrl_handler, &ctrl)) { - dev_warn(isp->dev, "failed to g_ctrl for f number range\n"); - return -EINVAL; - } else { - config->f_number_range = ctrl.value; - } - - return 0; -} - int atomisp_offline_capture_configure(struct atomisp_sub_device *asd, struct atomisp_cont_capture_conf *cvf_config) { diff --git a/drivers/staging/media/atomisp/pci/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp_cmd.h index b8911491581a..733b9f8cd06f 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_cmd.h +++ b/drivers/staging/media/atomisp/pci/atomisp_cmd.h @@ -57,7 +57,8 @@ struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev); int atomisp_reset(struct atomisp_device *isp); int atomisp_buffers_in_css(struct atomisp_video_pipe *pipe); void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state); -void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames); +void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, enum vb2_buffer_state state, + bool warn_on_css_frames); void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd); void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd); @@ -258,9 +259,6 @@ int atomisp_makeup_css_parameters(struct atomisp_sub_device *asd, int atomisp_compare_grid(struct atomisp_sub_device *asd, struct atomisp_grid_info *atomgrid); -int atomisp_get_sensor_mode_data(struct atomisp_sub_device *asd, - struct atomisp_sensor_mode_data *config); - /* This function looks up the closest available resolution. */ int atomisp_try_fmt(struct video_device *vdev, struct v4l2_pix_format *f, bool *res_overflow); @@ -273,9 +271,6 @@ int atomisp_set_shading_table(struct atomisp_sub_device *asd, int atomisp_offline_capture_configure(struct atomisp_sub_device *asd, struct atomisp_cont_capture_conf *cvf_config); -int atomisp_exif_makernote(struct atomisp_sub_device *asd, - struct atomisp_makernote_info *config); - void atomisp_free_internal_buffers(struct atomisp_sub_device *asd); int atomisp_s_ae_window(struct atomisp_sub_device *asd, diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp_csi2.c index 4a9268bac8a9..b00bc0b7aaad 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.c @@ -175,47 +175,8 @@ static const struct v4l2_subdev_ops csi2_ops = { .pad = &csi2_pad_ops, }; -/* - * csi2_link_setup - Setup CSI2 connections. - * @entity : Pointer to media entity structure - * @local : Pointer to local pad array - * @remote : Pointer to remote pad array - * @flags : Link flags - * return -EINVAL or zero on success - */ -static int csi2_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct atomisp_mipi_csi2_device *csi2 = v4l2_get_subdevdata(sd); - u32 result = local->index | is_media_entity_v4l2_subdev(remote->entity); - - switch (result) { - case CSI2_PAD_SOURCE | MEDIA_ENT_F_OLD_BASE: - /* not supported yet */ - return -EINVAL; - - case CSI2_PAD_SOURCE | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN: - if (flags & MEDIA_LNK_FL_ENABLED) { - if (csi2->output & ~CSI2_OUTPUT_ISP_SUBDEV) - return -EBUSY; - csi2->output |= CSI2_OUTPUT_ISP_SUBDEV; - } else { - csi2->output &= ~CSI2_OUTPUT_ISP_SUBDEV; - } - break; - - default: - /* Link from camera to CSI2 is fixed... */ - return -EINVAL; - } - return 0; -} - /* media operations */ static const struct media_entity_operations csi2_media_ops = { - .link_setup = csi2_link_setup, .link_validate = v4l2_subdev_link_validate, }; @@ -242,7 +203,7 @@ static int mipi_csi2_init_entities(struct atomisp_mipi_csi2_device *csi2, pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; me->ops = &csi2_media_ops; - me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; + me->function = MEDIA_ENT_F_VID_IF_BRIDGE; ret = media_entity_pads_init(me, CSI2_PADS_NUM, pads); if (ret < 0) return ret; diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.h b/drivers/staging/media/atomisp/pci/atomisp_csi2.h index e35711be8a37..b245b2f5ce99 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.h +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.h @@ -25,9 +25,6 @@ #define CSI2_PAD_SOURCE 1 #define CSI2_PADS_NUM 2 -#define CSI2_OUTPUT_ISP_SUBDEV BIT(0) -#define CSI2_OUTPUT_MEMORY BIT(1) - struct atomisp_device; struct v4l2_device; struct atomisp_sub_device; @@ -39,8 +36,6 @@ struct atomisp_mipi_csi2_device { struct v4l2_ctrl_handler ctrls; struct atomisp_device *isp; - - u32 output; /* output direction */ }; int atomisp_csi2_set_ffmt(struct v4l2_subdev *sd, diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp_fops.c index acea7492847d..ce01479bdd68 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.c @@ -80,7 +80,7 @@ static int atomisp_queue_setup(struct vb2_queue *vq, out: mutex_unlock(&pipe->asd->isp->mutex); - return 0; + return ret; } static int atomisp_buf_init(struct vb2_buffer *vb) @@ -624,7 +624,7 @@ static void atomisp_buf_cleanup(struct vb2_buffer *vb) hmm_free(frame->data); } -static const struct vb2_ops atomisp_vb2_ops = { +const struct vb2_ops atomisp_vb2_ops = { .queue_setup = atomisp_queue_setup, .buf_init = atomisp_buf_init, .buf_cleanup = atomisp_buf_cleanup, @@ -633,40 +633,6 @@ static const struct vb2_ops atomisp_vb2_ops = { .stop_streaming = atomisp_stop_streaming, }; -static int atomisp_init_pipe(struct atomisp_video_pipe *pipe) -{ - int ret; - - /* init locks */ - spin_lock_init(&pipe->irq_lock); - mutex_init(&pipe->vb_queue_mutex); - - /* Init videobuf2 queue structure */ - pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR; - pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame); - pipe->vb_queue.ops = &atomisp_vb2_ops; - pipe->vb_queue.mem_ops = &vb2_vmalloc_memops; - pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - ret = vb2_queue_init(&pipe->vb_queue); - if (ret) - return ret; - - pipe->vdev.queue = &pipe->vb_queue; - pipe->vdev.queue->lock = &pipe->vb_queue_mutex; - - INIT_LIST_HEAD(&pipe->activeq); - INIT_LIST_HEAD(&pipe->buffers_waiting_for_param); - INIT_LIST_HEAD(&pipe->per_frame_params); - memset(pipe->frame_request_config_id, 0, - VIDEO_MAX_FRAME * sizeof(unsigned int)); - memset(pipe->frame_params, 0, - VIDEO_MAX_FRAME * - sizeof(struct atomisp_css_params_with_list *)); - - return 0; -} - static void atomisp_dev_init_struct(struct atomisp_device *isp) { unsigned int i; @@ -681,7 +647,7 @@ static void atomisp_dev_init_struct(struct atomisp_device *isp) * For Merrifield, frequency is scalable. * After boot-up, the default frequency is 200MHz. */ - isp->sw_contex.running_freq = ISP_FREQ_200MHZ; + isp->running_freq = ISP_FREQ_200MHZ; } static void atomisp_subdev_init_struct(struct atomisp_sub_device *asd) @@ -757,25 +723,6 @@ static int atomisp_open(struct file *file) mutex_lock(&isp->mutex); asd->subdev.devnode = vdev; - /* Deferred firmware loading case. */ - if (isp->css_env.isp_css_fw.bytes == 0) { - dev_err(isp->dev, "Deferred firmware load.\n"); - isp->firmware = atomisp_load_firmware(isp); - if (!isp->firmware) { - dev_err(isp->dev, "Failed to load ISP firmware.\n"); - ret = -ENOENT; - goto error; - } - ret = atomisp_css_load_firmware(isp); - if (ret) { - dev_err(isp->dev, "Failed to init css.\n"); - goto error; - } - /* No need to keep FW in memory anymore. */ - release_firmware(isp->firmware); - isp->firmware = NULL; - isp->css_env.isp_css_fw.data = NULL; - } if (!isp->input_cnt) { dev_err(isp->dev, "no camera attached\n"); @@ -792,10 +739,6 @@ static int atomisp_open(struct file *file) return -EBUSY; } - ret = atomisp_init_pipe(pipe); - if (ret) - goto error; - if (atomisp_dev_users(isp)) { dev_dbg(isp->dev, "skip init isp in open\n"); goto init_subdev; @@ -821,13 +764,13 @@ init_subdev: goto done; atomisp_subdev_init_struct(asd); + /* Ensure that a mode is set */ + v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode); done: pipe->users++; mutex_unlock(&isp->mutex); - /* Ensure that a mode is set */ - v4l2_ctrl_s_ctrl(asd->run_mode, pipe->default_run_mode); return 0; @@ -885,13 +828,17 @@ static int atomisp_release(struct file *file) atomisp_css_free_stat_buffers(asd); atomisp_free_internal_buffers(asd); - ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, - core, s_power, 0); - if (ret) - dev_warn(isp->dev, "Failed to power-off sensor\n"); - /* clear the asd field to show this camera is not used */ - isp->inputs[asd->input_curr].asd = NULL; + if (isp->inputs[asd->input_curr].asd == asd) { + ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, + core, s_power, 0); + if (ret && ret != -ENOIOCTLCMD) + dev_warn(isp->dev, "Failed to power-off sensor\n"); + + /* clear the asd field to show this camera is not used */ + isp->inputs[asd->input_curr].asd = NULL; + } + spin_lock_irqsave(&isp->lock, flags); asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED; spin_unlock_irqrestore(&isp->lock, flags); @@ -901,12 +848,6 @@ static int atomisp_release(struct file *file) atomisp_destroy_pipes_stream_force(asd); - if (defer_fw_load) { - ia_css_unload_firmware(); - isp->css_env.isp_css_fw.data = NULL; - isp->css_env.isp_css_fw.bytes = 0; - } - ret = v4l2_subdev_call(isp->flash, core, s_power, 0); if (ret < 0 && ret != -ENODEV && ret != -ENOIOCTLCMD) dev_warn(isp->dev, "Failed to power-off flash\n"); diff --git a/drivers/staging/media/atomisp/pci/atomisp_fops.h b/drivers/staging/media/atomisp/pci/atomisp_fops.h index 10e43126b693..883c1851c1c9 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_fops.h +++ b/drivers/staging/media/atomisp/pci/atomisp_fops.h @@ -31,8 +31,7 @@ unsigned int atomisp_sub_dev_users(struct atomisp_sub_device *asd); int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd); +extern const struct vb2_ops atomisp_vb2_ops; extern const struct v4l2_file_operations atomisp_fops; -extern bool defer_fw_load; - #endif /* __ATOMISP_FOPS_H__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index 3d41fab661cf..7fc7dfa56172 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -57,8 +57,12 @@ enum clock_rate { #define LDO_1P8V_OFF 0x58 /* ... bottom bit is "enabled" */ /* CRYSTAL COVE PMIC register set */ -#define CRYSTAL_1P8V_REG 0x57 -#define CRYSTAL_2P8V_REG 0x5d +#define CRYSTAL_BYT_1P8V_REG 0x5d +#define CRYSTAL_BYT_2P8V_REG 0x66 + +#define CRYSTAL_CHT_1P8V_REG 0x57 +#define CRYSTAL_CHT_2P8V_REG 0x5d + #define CRYSTAL_ON 0x63 #define CRYSTAL_OFF 0x62 @@ -145,7 +149,6 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev, enum intel_v4l2_subdev_type type) { int i; - struct i2c_board_info *bi; struct gmin_subdev *gs; struct i2c_client *client = v4l2_get_subdevdata(subdev); struct acpi_device *adev = ACPI_COMPANION(&client->dev); @@ -158,6 +161,14 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev, * tickled during suspend/resume. This has caused power and * performance issues on multiple devices. */ + + /* + * Turn off the device before disabling ACPI power resources + * (the sensor driver has already probed it at this point). + * This avoids leaking the reference count of the (possibly shared) + * ACPI power resources which were enabled/referenced before probe(). + */ + acpi_device_set_power(adev, ACPI_STATE_D3_COLD); adev->power.flags.power_resources = 0; for (i = 0; i < MAX_SUBDEVS; i++) @@ -179,36 +190,10 @@ int atomisp_register_i2c_module(struct v4l2_subdev *subdev, pdata.subdevs[i].type = type; pdata.subdevs[i].port = gs->csi_port; pdata.subdevs[i].subdev = subdev; - pdata.subdevs[i].v4l2_subdev.i2c_adapter_id = client->adapter->nr; - - /* Convert i2c_client to i2c_board_info */ - bi = &pdata.subdevs[i].v4l2_subdev.board_info; - memcpy(bi->type, client->name, I2C_NAME_SIZE); - bi->flags = client->flags; - bi->addr = client->addr; - bi->irq = client->irq; - bi->platform_data = plat_data; - return 0; } EXPORT_SYMBOL_GPL(atomisp_register_i2c_module); -struct v4l2_subdev *atomisp_gmin_find_subdev(struct i2c_adapter *adapter, - struct i2c_board_info *board_info) -{ - int i; - - for (i = 0; i < MAX_SUBDEVS && pdata.subdevs[i].type; i++) { - struct intel_v4l2_subdev_table *sd = &pdata.subdevs[i]; - - if (sd->v4l2_subdev.i2c_adapter_id == adapter->nr && - sd->v4l2_subdev.board_info.addr == board_info->addr) - return sd->subdev; - } - return NULL; -} -EXPORT_SYMBOL_GPL(atomisp_gmin_find_subdev); - int atomisp_gmin_remove_subdev(struct v4l2_subdev *sd) { int i, j; @@ -843,6 +828,7 @@ static int gmin_v1p8_ctrl(struct v4l2_subdev *subdev, int on) struct gmin_subdev *gs = find_gmin_subdev(subdev); int ret; int value; + int reg; if (!gs || gs->v1p8_on == on) return 0; @@ -898,10 +884,15 @@ static int gmin_v1p8_ctrl(struct v4l2_subdev *subdev, int on) LDO10_REG, value, 0xff); break; case PMIC_CRYSTALCOVE: + if (IS_ISP2401) + reg = CRYSTAL_CHT_1P8V_REG; + else + reg = CRYSTAL_BYT_1P8V_REG; + value = on ? CRYSTAL_ON : CRYSTAL_OFF; ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, - CRYSTAL_1P8V_REG, value, 0xff); + reg, value, 0xff); break; default: dev_err(subdev->dev, "Couldn't set power mode for v1p8\n"); @@ -918,6 +909,7 @@ static int gmin_v2p8_ctrl(struct v4l2_subdev *subdev, int on) struct gmin_subdev *gs = find_gmin_subdev(subdev); int ret; int value; + int reg; if (WARN_ON(!gs)) return -ENODEV; @@ -974,10 +966,15 @@ static int gmin_v2p8_ctrl(struct v4l2_subdev *subdev, int on) LDO9_REG, value, 0xff); break; case PMIC_CRYSTALCOVE: + if (IS_ISP2401) + reg = CRYSTAL_CHT_2P8V_REG; + else + reg = CRYSTAL_BYT_2P8V_REG; + value = on ? CRYSTAL_ON : CRYSTAL_OFF; ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, - CRYSTAL_2P8V_REG, value, 0xff); + reg, value, 0xff); break; default: dev_err(subdev->dev, "Couldn't set power mode for v2p8\n"); @@ -1095,6 +1092,67 @@ static int gmin_csi_cfg(struct v4l2_subdev *sd, int flag) return 0; } +int atomisp_register_sensor_no_gmin(struct v4l2_subdev *subdev, u32 lanes, + enum atomisp_input_format format, + enum atomisp_bayer_order bayer_order) +{ + struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct acpi_device *adev = ACPI_COMPANION(&client->dev); + int i, ret, clock_num, port = 0; + + if (adev) { + /* Get ACPI _PR0 derived clock to determine the csi_port default */ + if (acpi_device_power_manageable(adev)) { + clock_num = atomisp_get_acpi_power(&client->dev); + + /* Compare clock to CsiPort 1 pmc-clock used in the CHT/BYT reference designs */ + if (IS_ISP2401) + port = clock_num == 4 ? 1 : 0; + else + port = clock_num == 0 ? 1 : 0; + } + + port = gmin_get_var_int(&client->dev, false, "CsiPort", port); + lanes = gmin_get_var_int(&client->dev, false, "CsiLanes", lanes); + } + + for (i = 0; i < MAX_SUBDEVS; i++) + if (!pdata.subdevs[i].type) + break; + + if (i >= MAX_SUBDEVS) { + dev_err(&client->dev, "Error too many subdevs already registered\n"); + return -ENOMEM; + } + + ret = camera_sensor_csi_alloc(subdev, port, lanes, format, bayer_order); + if (ret) + return ret; + + pdata.subdevs[i].type = RAW_CAMERA; + pdata.subdevs[i].port = port; + pdata.subdevs[i].subdev = subdev; + return 0; +} +EXPORT_SYMBOL_GPL(atomisp_register_sensor_no_gmin); + +void atomisp_unregister_subdev(struct v4l2_subdev *subdev) +{ + int i; + + for (i = 0; i < MAX_SUBDEVS; i++) { + if (pdata.subdevs[i].subdev != subdev) + continue; + + camera_sensor_csi_free(subdev); + pdata.subdevs[i].subdev = NULL; + pdata.subdevs[i].type = 0; + pdata.subdevs[i].port = 0; + break; + } +} +EXPORT_SYMBOL_GPL(atomisp_unregister_subdev); + static struct camera_vcm_control *gmin_get_vcm_ctrl(struct v4l2_subdev *subdev, char *camera_module) { diff --git a/drivers/staging/media/atomisp/pci/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp_internal.h index 653e6d74a966..fa38d91420cf 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_internal.h +++ b/drivers/staging/media/atomisp/pci/atomisp_internal.h @@ -194,10 +194,6 @@ struct atomisp_regs { u32 csi_access_viol; }; -struct atomisp_sw_contex { - int running_freq; -}; - #define ATOMISP_DEVICE_STREAMING_DISABLED 0 #define ATOMISP_DEVICE_STREAMING_ENABLED 1 #define ATOMISP_DEVICE_STREAMING_STOPPING 2 @@ -214,6 +210,7 @@ struct atomisp_device { void __iomem *base; const struct firmware *firmware; + struct dev_pm_domain pm_domain; struct pm_qos_request pm_qos; s32 max_isr_latency; @@ -242,7 +239,6 @@ struct atomisp_device { struct v4l2_subdev *motor; struct atomisp_regs saved_regs; - struct atomisp_sw_contex sw_contex; struct atomisp_css_env css_env; /* isp timeout status flag */ @@ -257,6 +253,7 @@ struct atomisp_device { unsigned int mipi_frame_size; const struct atomisp_dfs_config *dfs; unsigned int hpll_freq; + unsigned int running_freq; bool css_initialized; }; diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c index cb01ba65c88f..d1314bdbf7d5 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c @@ -173,24 +173,6 @@ static struct v4l2_queryctrl ci_v4l2_controls[] = { .default_value = 1, }, { - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Horizontal binning factor", - .minimum = 0, - .maximum = 10, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Vertical binning factor", - .minimum = 0, - .maximum = 10, - .step = 1, - .default_value = 0, - }, - { .id = V4L2_CID_2A_STATUS, .type = V4L2_CTRL_TYPE_BITMASK, .name = "AE and AWB status", @@ -636,10 +618,10 @@ static int atomisp_enum_input(struct file *file, void *fh, static unsigned int atomisp_subdev_streaming_count(struct atomisp_sub_device *asd) { - return asd->video_out_preview.vb_queue.start_streaming_called - + asd->video_out_capture.vb_queue.start_streaming_called - + asd->video_out_video_capture.vb_queue.start_streaming_called - + asd->video_out_vf.vb_queue.start_streaming_called; + return vb2_start_streaming_called(&asd->video_out_preview.vb_queue) + + vb2_start_streaming_called(&asd->video_out_capture.vb_queue) + + vb2_start_streaming_called(&asd->video_out_video_capture.vb_queue) + + vb2_start_streaming_called(&asd->video_out_vf.vb_queue); } unsigned int atomisp_streaming_count(struct atomisp_device *isp) @@ -718,7 +700,7 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input) asd->input_curr != input) { ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, core, s_power, 0); - if (ret) + if (ret && ret != -ENOIOCTLCMD) dev_warn(isp->dev, "Failed to power-off sensor\n"); /* clear the asd field to show this camera is not used */ @@ -727,7 +709,7 @@ static int atomisp_s_input(struct file *file, void *fh, unsigned int input) /* powe on the new sensor */ ret = v4l2_subdev_call(isp->inputs[input].camera, core, s_power, 1); - if (ret) { + if (ret && ret != -ENOIOCTLCMD) { dev_err(isp->dev, "Failed to power-on sensor\n"); return ret; } @@ -1067,13 +1049,23 @@ error: return -ENOMEM; } +/* + * FIXME the abuse of buf->reserved2 in the qbuf and dqbuf wrappers comes from + * the original atomisp buffer handling and should be replaced with proper V4L2 + * per frame parameters use. + * + * Once this is fixed these wrappers can be removed, replacing them with direct + * calls to vb2_ioctl_[d]qbuf(). + */ static int atomisp_qbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer *buf) { struct video_device *vdev = video_devdata(file); struct atomisp_device *isp = video_get_drvdata(vdev); struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); - /* FIXME this abuse of buf->reserved2 comes from the original atomisp buffer handling */ + if (buf->index >= vdev->queue->num_buffers) + return -EINVAL; + if (!atomisp_is_vf_pipe(pipe) && (buf->reserved2 & ATOMISP_BUFFER_HAS_PER_FRAME_SETTING)) { /* this buffer will have a per-frame parameter */ @@ -1106,7 +1098,6 @@ static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer vb = pipe->vb_queue.bufs[buf->index]; frame = vb_to_frame(vb); - /* FIXME this abuse of buf->reserved* comes from the original atomisp buffer handling */ buf->reserved = asd->frame_status[buf->index]; /* @@ -1354,7 +1345,7 @@ int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count) ret = atomisp_css_start(asd, css_pipe_id, false); if (ret) { - atomisp_flush_video_pipe(pipe, true); + atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_QUEUED, true); goto out_unlock; } @@ -1530,7 +1521,7 @@ void atomisp_stop_streaming(struct vb2_queue *vq) css_pipe_id = atomisp_get_css_pipe_id(asd); atomisp_css_stop(asd, css_pipe_id, false); - atomisp_flush_video_pipe(pipe, true); + atomisp_flush_video_pipe(pipe, VB2_BUF_STATE_ERROR, true); atomisp_subdev_cleanup_pending_events(asd); stopsensor: @@ -1631,7 +1622,6 @@ static int atomisp_g_ctrl(struct file *file, void *fh, switch (control->id) { case V4L2_CID_IRIS_ABSOLUTE: case V4L2_CID_EXPOSURE_ABSOLUTE: - case V4L2_CID_FNUMBER_ABSOLUTE: case V4L2_CID_2A_STATUS: case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: case V4L2_CID_EXPOSURE: @@ -1828,9 +1818,6 @@ static int atomisp_camera_g_ext_ctrls(struct file *file, void *fh, case V4L2_CID_EXPOSURE_ABSOLUTE: case V4L2_CID_EXPOSURE_AUTO: case V4L2_CID_IRIS_ABSOLUTE: - case V4L2_CID_FNUMBER_ABSOLUTE: - case V4L2_CID_BIN_FACTOR_HORZ: - case V4L2_CID_BIN_FACTOR_VERT: case V4L2_CID_3A_LOCK: case V4L2_CID_TEST_PATTERN: case V4L2_CID_TEST_PATTERN_COLOR_R: @@ -1940,7 +1927,6 @@ static int atomisp_camera_s_ext_ctrls(struct file *file, void *fh, case V4L2_CID_EXPOSURE_AUTO: case V4L2_CID_EXPOSURE_METERING: case V4L2_CID_IRIS_ABSOLUTE: - case V4L2_CID_FNUMBER_ABSOLUTE: case V4L2_CID_VCM_TIMING: case V4L2_CID_VCM_SLEW: case V4L2_CID_3A_LOCK: @@ -2276,14 +2262,6 @@ static long atomisp_vidioc_default(struct file *file, void *fh, err = atomisp_fixed_pattern_table(asd, arg); break; - case ATOMISP_IOC_ISP_MAKERNOTE: - err = atomisp_exif_makernote(asd, arg); - break; - - case ATOMISP_IOC_G_SENSOR_MODE_DATA: - err = atomisp_get_sensor_mode_data(asd, arg); - break; - case ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA: if (motor) err = v4l2_subdev_call(motor, core, ioctl, cmd, arg); diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c index cadc468b4c2f..9cfb85c61db6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c @@ -25,9 +25,11 @@ #include <media/v4l2-event.h> #include <media/v4l2-mediabus.h> +#include <media/videobuf2-vmalloc.h> #include "atomisp_cmd.h" #include "atomisp_common.h" #include "atomisp_compat.h" +#include "atomisp_fops.h" #include "atomisp_internal.h" const struct atomisp_in_fmt_conv atomisp_in_fmt_conv[] = { @@ -574,40 +576,6 @@ static int isp_subdev_set_selection(struct v4l2_subdev *sd, sel->target, sel->flags, &sel->r); } -static int atomisp_get_sensor_bin_factor(struct atomisp_sub_device *asd) -{ - struct v4l2_control ctrl = {0}; - struct atomisp_device *isp = asd->isp; - int hbin, vbin; - int ret; - - if (isp->inputs[asd->input_curr].type == FILE_INPUT || - isp->inputs[asd->input_curr].type == TEST_PATTERN) - return 0; - - ctrl.id = V4L2_CID_BIN_FACTOR_HORZ; - ret = - v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler, - &ctrl); - hbin = ctrl.value; - ctrl.id = V4L2_CID_BIN_FACTOR_VERT; - ret |= - v4l2_g_ctrl(isp->inputs[asd->input_curr].camera->ctrl_handler, - &ctrl); - vbin = ctrl.value; - - /* - * ISP needs to know binning factor from sensor. - * In case horizontal and vertical sensor's binning factors - * are different or sensor does not support binning factor CID, - * ISP will apply default 0 value. - */ - if (ret || hbin != vbin) - hbin = 0; - - return hbin; -} - void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, uint32_t which, @@ -645,7 +613,7 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, ATOMISP_INPUT_STREAM_GENERAL, ffmt); atomisp_css_input_set_binning_factor(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, - atomisp_get_sensor_bin_factor(isp_sd)); + 0); atomisp_css_input_set_bayer_order(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, fc->bayer_order); atomisp_css_input_set_format(isp_sd, ATOMISP_INPUT_STREAM_GENERAL, @@ -746,85 +714,8 @@ static void isp_subdev_init_params(struct atomisp_sub_device *asd) } } -/* -* isp_subdev_link_setup - Setup isp subdev connections -* @entity: ispsubdev media entity -* @local: Pad at the local end of the link -* @remote: Pad at the remote end of the link -* @flags: Link flags -* -* return -EINVAL or zero on success -*/ -static int isp_subdev_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct atomisp_sub_device *isp_sd = v4l2_get_subdevdata(sd); - struct atomisp_device *isp = isp_sd->isp; - unsigned int i; - - switch (local->index | is_media_entity_v4l2_subdev(remote->entity)) { - case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN: - /* Read from the sensor CSI2-ports. */ - if (!(flags & MEDIA_LNK_FL_ENABLED)) { - isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE; - break; - } - - if (isp_sd->input != ATOMISP_SUBDEV_INPUT_NONE) - return -EBUSY; - - for (i = 0; i < ATOMISP_CAMERA_NR_PORTS; i++) { - if (remote->entity != &isp->csi2_port[i].subdev.entity) - continue; - - isp_sd->input = ATOMISP_SUBDEV_INPUT_CSI2_PORT1 + i; - return 0; - } - - return -EINVAL; - - case ATOMISP_SUBDEV_PAD_SINK | MEDIA_ENT_F_OLD_BASE: - /* read from memory */ - if (flags & MEDIA_LNK_FL_ENABLED) { - if (isp_sd->input >= ATOMISP_SUBDEV_INPUT_CSI2_PORT1 && - isp_sd->input < (ATOMISP_SUBDEV_INPUT_CSI2_PORT1 - + ATOMISP_CAMERA_NR_PORTS)) - return -EBUSY; - isp_sd->input = ATOMISP_SUBDEV_INPUT_MEMORY; - } else { - if (isp_sd->input == ATOMISP_SUBDEV_INPUT_MEMORY) - isp_sd->input = ATOMISP_SUBDEV_INPUT_NONE; - } - break; - - case ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW | MEDIA_ENT_F_OLD_BASE: - /* always write to memory */ - break; - - case ATOMISP_SUBDEV_PAD_SOURCE_VF | MEDIA_ENT_F_OLD_BASE: - /* always write to memory */ - break; - - case ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE | MEDIA_ENT_F_OLD_BASE: - /* always write to memory */ - break; - - case ATOMISP_SUBDEV_PAD_SOURCE_VIDEO | MEDIA_ENT_F_OLD_BASE: - /* always write to memory */ - break; - - default: - return -EINVAL; - } - - return 0; -} - /* media operations */ static const struct media_entity_operations isp_subdev_media_ops = { - .link_setup = isp_subdev_link_setup, .link_validate = v4l2_subdev_link_validate, /* .set_power = v4l2_subdev_set_power, */ }; @@ -1057,23 +948,37 @@ static const struct v4l2_ctrl_config ctrl_depth_mode = { .def = 0, }; -static void atomisp_init_subdev_pipe(struct atomisp_sub_device *asd, - struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type) +static int atomisp_init_subdev_pipe(struct atomisp_sub_device *asd, + struct atomisp_video_pipe *pipe, enum v4l2_buf_type buf_type) { + int ret; + pipe->type = buf_type; pipe->asd = asd; pipe->isp = asd->isp; spin_lock_init(&pipe->irq_lock); mutex_init(&pipe->vb_queue_mutex); + + /* Init videobuf2 queue structure */ + pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR; + pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame); + pipe->vb_queue.ops = &atomisp_vb2_ops; + pipe->vb_queue.mem_ops = &vb2_vmalloc_memops; + pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + ret = vb2_queue_init(&pipe->vb_queue); + if (ret) + return ret; + + pipe->vdev.queue = &pipe->vb_queue; + pipe->vdev.queue->lock = &pipe->vb_queue_mutex; + INIT_LIST_HEAD(&pipe->buffers_in_css); INIT_LIST_HEAD(&pipe->activeq); INIT_LIST_HEAD(&pipe->buffers_waiting_for_param); INIT_LIST_HEAD(&pipe->per_frame_params); - memset(pipe->frame_request_config_id, - 0, VIDEO_MAX_FRAME * sizeof(unsigned int)); - memset(pipe->frame_params, - 0, VIDEO_MAX_FRAME * - sizeof(struct atomisp_css_params_with_list *)); + + return 0; } /* @@ -1089,8 +994,6 @@ static int isp_subdev_init_entities(struct atomisp_sub_device *asd) struct media_entity *me = &sd->entity; int ret; - asd->input = ATOMISP_SUBDEV_INPUT_NONE; - v4l2_subdev_init(sd, &isp_subdev_v4l2_ops); sprintf(sd->name, "ATOMISP_SUBDEV_%d", asd->index); v4l2_set_subdevdata(sd, asd); @@ -1114,22 +1017,30 @@ static int isp_subdev_init_entities(struct atomisp_sub_device *asd) MEDIA_BUS_FMT_SBGGR10_1X10; me->ops = &isp_subdev_media_ops; - me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; + me->function = MEDIA_ENT_F_PROC_VIDEO_ISP; ret = media_entity_pads_init(me, ATOMISP_SUBDEV_PADS_NUM, pads); if (ret < 0) return ret; - atomisp_init_subdev_pipe(asd, &asd->video_out_preview, - V4L2_BUF_TYPE_VIDEO_CAPTURE); + ret = atomisp_init_subdev_pipe(asd, &asd->video_out_preview, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (ret) + return ret; - atomisp_init_subdev_pipe(asd, &asd->video_out_vf, - V4L2_BUF_TYPE_VIDEO_CAPTURE); + ret = atomisp_init_subdev_pipe(asd, &asd->video_out_vf, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (ret) + return ret; - atomisp_init_subdev_pipe(asd, &asd->video_out_capture, - V4L2_BUF_TYPE_VIDEO_CAPTURE); + ret = atomisp_init_subdev_pipe(asd, &asd->video_out_capture, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (ret) + return ret; - atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture, - V4L2_BUF_TYPE_VIDEO_CAPTURE); + ret = atomisp_init_subdev_pipe(asd, &asd->video_out_video_capture, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (ret) + return ret; ret = atomisp_video_init(&asd->video_out_capture, "CAPTURE", ATOMISP_RUN_MODE_STILL_CAPTURE); diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.h b/drivers/staging/media/atomisp/pci/atomisp_subdev.h index bd2872cbb50c..daa6077a83bd 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.h +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.h @@ -30,18 +30,6 @@ /* EXP_ID's ranger is 1 ~ 250 */ #define ATOMISP_MAX_EXP_ID (250) -enum atomisp_subdev_input_entity { - ATOMISP_SUBDEV_INPUT_NONE, - ATOMISP_SUBDEV_INPUT_MEMORY, - ATOMISP_SUBDEV_INPUT_CSI2, - /* - * The following enum for CSI2 port must go together in one row. - * Otherwise it breaks the code logic. - */ - ATOMISP_SUBDEV_INPUT_CSI2_PORT1, - ATOMISP_SUBDEV_INPUT_CSI2_PORT2, - ATOMISP_SUBDEV_INPUT_CSI2_PORT3, -}; #define ATOMISP_SUBDEV_PAD_SINK 0 /* capture output for still frames */ @@ -267,7 +255,6 @@ struct atomisp_sub_device { struct atomisp_pad_format fmt[ATOMISP_SUBDEV_PADS_NUM]; u16 capture_pad; /* main capture pad; defines much of isp config */ - enum atomisp_subdev_input_entity input; unsigned int output; struct atomisp_video_pipe video_out_capture; /* capture output */ struct atomisp_video_pipe video_out_vf; /* viewfinder output */ diff --git a/drivers/staging/media/atomisp/pci/atomisp_tpg.c b/drivers/staging/media/atomisp/pci/atomisp_tpg.c index e29a96da5f98..074826a5b706 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_tpg.c +++ b/drivers/staging/media/atomisp/pci/atomisp_tpg.c @@ -152,7 +152,7 @@ int atomisp_tpg_init(struct atomisp_device *isp) v4l2_set_subdevdata(sd, tpg); pads[0].flags = MEDIA_PAD_FL_SINK; - me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; + me->function = MEDIA_ENT_F_PROC_VIDEO_ISP; ret = media_entity_pads_init(me, 1, pads); if (ret < 0) diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index e786b81921da..ba628f7cf385 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -19,6 +19,7 @@ */ #include <linux/module.h> #include <linux/pci.h> +#include <linux/pm_domain.h> #include <linux/pm_runtime.h> #include <linux/pm_qos.h> #include <linux/timer.h> @@ -57,12 +58,6 @@ static uint skip_fwload; module_param(skip_fwload, uint, 0644); MODULE_PARM_DESC(skip_fwload, "Skip atomisp firmware load"); -/* memory optimization: deferred firmware loading */ -bool defer_fw_load; -module_param(defer_fw_load, bool, 0644); -MODULE_PARM_DESC(defer_fw_load, - "Defer FW loading until device is opened (default:disable)"); - /* cross componnet debug message flag */ int dbg_level; module_param(dbg_level, int, 0644); @@ -524,7 +519,7 @@ static int atomisp_save_iunit_reg(struct atomisp_device *isp) return 0; } -static int __maybe_unused atomisp_restore_iunit_reg(struct atomisp_device *isp) +static int atomisp_restore_iunit_reg(struct atomisp_device *isp) { struct pci_dev *pdev = to_pci_dev(isp->dev); @@ -637,31 +632,21 @@ done: */ static void punit_ddr_dvfs_enable(bool enable) { - int door_bell = 1 << 8; - int max_wait = 30; int reg; iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSDVFS, ®); if (enable) { reg &= ~(MRFLD_BIT0 | MRFLD_BIT1); } else { - reg |= (MRFLD_BIT1 | door_bell); + reg |= MRFLD_BIT1; reg &= ~(MRFLD_BIT0); } iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, MRFLD_ISPSSDVFS, reg); - - /* Check Req_ACK to see freq status, wait until door_bell is cleared */ - while ((reg & door_bell) && max_wait--) { - iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSDVFS, ®); - usleep_range(100, 500); - } - - if (max_wait == -1) - pr_info("DDR DVFS, door bell is not cleared within 3ms\n"); } static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable) { + struct pci_dev *pdev = to_pci_dev(isp->dev); unsigned long timeout; u32 val = enable ? MRFLD_ISPSSPM0_IUNIT_POWER_ON : MRFLD_ISPSSPM0_IUNIT_POWER_OFF; @@ -669,16 +654,10 @@ static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable) dev_dbg(isp->dev, "IUNIT power-%s.\n", enable ? "on" : "off"); /* WA for P-Unit, if DVFS enabled, ISP timeout observed */ - if (IS_CHT && enable) + if (IS_CHT && enable) { punit_ddr_dvfs_enable(false); - - /* - * FIXME:WA for ECS28A, with this sleep, CTS - * android.hardware.camera2.cts.CameraDeviceTest#testCameraDeviceAbort - * PASS, no impact on other platforms - */ - if (IS_BYT && enable) - msleep(10); + msleep(20); + } /* Write to ISPSSPM0 bit[1:0] to power on/off the IUNIT */ iosf_mbi_modify(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSPM0, @@ -703,6 +682,7 @@ static int atomisp_mrfld_power(struct atomisp_device *isp, bool enable) tmp = (tmp >> MRFLD_ISPSSPM0_ISPSSS_OFFSET) & MRFLD_ISPSSPM0_ISPSSC_MASK; if (tmp == val) { trace_ipu_cstate(enable); + pdev->current_state = enable ? PCI_D0 : PCI_D3cold; return 0; } @@ -743,6 +723,7 @@ int atomisp_power_off(struct device *dev) pci_write_config_dword(pdev, MRFLD_PCI_CSI_CONTROL, reg); cpu_latency_qos_update_request(&isp->pm_qos, PM_QOS_DEFAULT_VALUE); + pci_save_state(pdev); return atomisp_mrfld_power(isp, false); } @@ -756,6 +737,7 @@ int atomisp_power_on(struct device *dev) if (ret) return ret; + pci_restore_state(to_pci_dev(dev)); cpu_latency_qos_update_request(&isp->pm_qos, isp->max_isr_latency); /*restore register values for iUnit and iUnitPHY registers*/ @@ -767,7 +749,7 @@ int atomisp_power_on(struct device *dev) return atomisp_css_init(isp); } -static int __maybe_unused atomisp_suspend(struct device *dev) +static int atomisp_suspend(struct device *dev) { struct atomisp_device *isp = (struct atomisp_device *) dev_get_drvdata(dev); @@ -790,10 +772,12 @@ static int __maybe_unused atomisp_suspend(struct device *dev) } spin_unlock_irqrestore(&isp->lock, flags); + pm_runtime_resume(dev); + return atomisp_power_off(dev); } -static int __maybe_unused atomisp_resume(struct device *dev) +static int atomisp_resume(struct device *dev) { return atomisp_power_on(dev); } @@ -953,45 +937,9 @@ static int atomisp_subdev_probe(struct atomisp_device *isp) /* FIXME: should, instead, use I2C probe */ for (subdevs = pdata->subdevs; subdevs->type; ++subdevs) { - struct v4l2_subdev *subdev; - struct i2c_board_info *board_info = - &subdevs->v4l2_subdev.board_info; - struct i2c_adapter *adapter = - i2c_get_adapter(subdevs->v4l2_subdev.i2c_adapter_id); - - dev_info(isp->dev, "Probing Subdev %s\n", board_info->type); - - if (!adapter) { - dev_err(isp->dev, - "Failed to find i2c adapter for subdev %s\n", - board_info->type); - break; - } - - /* In G-Min, the sensor devices will already be probed - * (via ACPI) and registered, do not create new - * ones */ - subdev = atomisp_gmin_find_subdev(adapter, board_info); - if (!subdev) { - dev_warn(isp->dev, "Subdev %s not found\n", - board_info->type); + ret = v4l2_device_register_subdev(&isp->v4l2_dev, subdevs->subdev); + if (ret) continue; - } - ret = v4l2_device_register_subdev(&isp->v4l2_dev, subdev); - if (ret) { - dev_warn(isp->dev, "Subdev %s detection fail\n", - board_info->type); - continue; - } - - if (!subdev) { - dev_warn(isp->dev, "Subdev %s detection fail\n", - board_info->type); - continue; - } - - dev_info(isp->dev, "Subdev %s successfully register\n", - board_info->type); switch (subdevs->type) { case RAW_CAMERA: @@ -1008,7 +956,7 @@ static int atomisp_subdev_probe(struct atomisp_device *isp) isp->inputs[isp->input_cnt].type = subdevs->type; isp->inputs[isp->input_cnt].port = subdevs->port; - isp->inputs[isp->input_cnt].camera = subdev; + isp->inputs[isp->input_cnt].camera = subdevs->subdev; isp->inputs[isp->input_cnt].sensor_index = 0; /* * initialize the subdev frame size, then next we can @@ -1020,22 +968,18 @@ static int atomisp_subdev_probe(struct atomisp_device *isp) break; case CAMERA_MOTOR: if (isp->motor) { - dev_warn(isp->dev, - "too many atomisp motors, ignored %s\n", - board_info->type); + dev_warn(isp->dev, "too many atomisp motors\n"); continue; } - isp->motor = subdev; + isp->motor = subdevs->subdev; break; case LED_FLASH: case XENON_FLASH: if (isp->flash) { - dev_warn(isp->dev, - "too many atomisp flash devices, ignored %s\n", - board_info->type); + dev_warn(isp->dev, "too many atomisp flash devices\n"); continue; } - isp->flash = subdev; + isp->flash = subdevs->subdev; break; default: dev_dbg(isp->dev, "unknown subdev probed\n"); @@ -1524,21 +1468,17 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i isp->max_isr_latency = ATOMISP_MAX_ISR_LATENCY; /* Load isp firmware from user space */ - if (!defer_fw_load) { - isp->firmware = atomisp_load_firmware(isp); - if (!isp->firmware) { - err = -ENOENT; - dev_dbg(&pdev->dev, "Firmware load failed\n"); - goto load_fw_fail; - } + isp->firmware = atomisp_load_firmware(isp); + if (!isp->firmware) { + err = -ENOENT; + dev_dbg(&pdev->dev, "Firmware load failed\n"); + goto load_fw_fail; + } - err = sh_css_check_firmware_version(isp->dev, isp->firmware->data); - if (err) { - dev_dbg(&pdev->dev, "Firmware version check failed\n"); - goto fw_validation_fail; - } - } else { - dev_info(&pdev->dev, "Firmware load will be deferred\n"); + err = sh_css_check_firmware_version(isp->dev, isp->firmware->data); + if (err) { + dev_dbg(&pdev->dev, "Firmware version check failed\n"); + goto fw_validation_fail; } pci_set_master(pdev); @@ -1603,6 +1543,26 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i /* save the iunit context only once after all the values are init'ed. */ atomisp_save_iunit_reg(isp); + /* + * The atomisp does not use standard PCI power-management through the + * PCI config space. Instead this driver directly tells the P-Unit to + * disable the ISP over the IOSF. The standard PCI subsystem pm_ops will + * try to access the config space before (resume) / after (suspend) this + * driver has turned the ISP on / off, resulting in the following errors: + * + * "Unable to change power state from D0 to D3hot, device inaccessible" + * "Unable to change power state from D3cold to D0, device inaccessible" + * + * To avoid these errors override the pm_domain so that all the PCI + * subsys suspend / resume handling is skipped. + */ + isp->pm_domain.ops.runtime_suspend = atomisp_power_off; + isp->pm_domain.ops.runtime_resume = atomisp_power_on; + isp->pm_domain.ops.suspend = atomisp_suspend; + isp->pm_domain.ops.resume = atomisp_resume; + + dev_pm_domain_set(&pdev->dev, &isp->pm_domain); + pm_runtime_put_noidle(&pdev->dev); pm_runtime_allow(&pdev->dev); @@ -1618,14 +1578,10 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i } /* Load firmware into ISP memory */ - if (!defer_fw_load) { - err = atomisp_css_load_firmware(isp); - if (err) { - dev_err(&pdev->dev, "Failed to init css.\n"); - goto css_init_fail; - } - } else { - dev_dbg(&pdev->dev, "Skip css init.\n"); + err = atomisp_css_load_firmware(isp); + if (err) { + dev_err(&pdev->dev, "Failed to init css.\n"); + goto css_init_fail; } /* Clear FW image from memory */ release_firmware(isp->firmware); @@ -1645,6 +1601,7 @@ css_init_fail: request_irq_fail: hmm_cleanup(); pm_runtime_get_noresume(&pdev->dev); + dev_pm_domain_set(&pdev->dev, NULL); atomisp_unregister_entities(isp); register_entities_fail: atomisp_uninitialize_modules(isp); @@ -1697,6 +1654,7 @@ static void atomisp_pci_remove(struct pci_dev *pdev) pm_runtime_forbid(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); + dev_pm_domain_set(&pdev->dev, NULL); cpu_latency_qos_remove_request(&isp->pm_qos); atomisp_msi_irq_uninit(isp); @@ -1721,17 +1679,8 @@ static const struct pci_device_id atomisp_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, atomisp_pci_tbl); -static const struct dev_pm_ops atomisp_pm_ops = { - .runtime_suspend = atomisp_power_off, - .runtime_resume = atomisp_power_on, - .suspend = atomisp_suspend, - .resume = atomisp_resume, -}; static struct pci_driver atomisp_pci_driver = { - .driver = { - .pm = &atomisp_pm_ops, - }, .name = "atomisp-isp2", .id_table = atomisp_pci_tbl, .probe = atomisp_pci_probe, diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h index a313e1dc7c71..d65fe9ec9049 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_dma_private.h @@ -34,8 +34,6 @@ void isys2401_dma_reg_store(const isys2401_dma_ID_t dma_id, reg_loc = ISYS2401_DMA_BASE[dma_id] + (reg * sizeof(hrt_data)); - ia_css_print("isys dma store at addr(0x%x) val(%u)\n", reg_loc, - (unsigned int)value); ia_css_device_store_uint32(reg_loc, value); } diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c index 6620f091442f..d9cdfbc50197 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/vmem.c @@ -28,10 +28,18 @@ typedef hive_uedge *hive_wide; /* Copied from SDK: sim_semantics.c */ /* subword bits move like this: MSB[____xxxx____]LSB -> MSB[00000000xxxx]LSB */ -#define SUBWORD(w, start, end) (((w) & (((1ULL << ((end) - 1)) - 1) << 1 | 1)) >> (start)) +static inline hive_uedge +subword(hive_uedge w, unsigned int start, unsigned int end) +{ + return (w & (((1ULL << (end - 1)) - 1) << 1 | 1)) >> start; +} /* inverse subword bits move like this: MSB[xxxx____xxxx]LSB -> MSB[xxxx0000xxxx]LSB */ -#define INV_SUBWORD(w, start, end) ((w) & (~(((1ULL << ((end) - 1)) - 1) << 1 | 1) | ((1ULL << (start)) - 1))) +static inline hive_uedge +inv_subword(hive_uedge w, unsigned int start, unsigned int end) +{ + return w & (~(((1ULL << (end - 1)) - 1) << 1 | 1) | ((1ULL << start) - 1)); +} #define uedge_bits (8 * sizeof(hive_uedge)) #define move_lower_bits(target, target_bit, src, src_bit) move_subword(target, target_bit, src, 0, src_bit) @@ -50,18 +58,18 @@ move_subword( unsigned int start_bit = target_bit % uedge_bits; unsigned int subword_width = src_end - src_start; - hive_uedge src_subword = SUBWORD(src, src_start, src_end); + hive_uedge src_subword = subword(src, src_start, src_end); if (subword_width + start_bit > uedge_bits) { /* overlap */ hive_uedge old_val1; - hive_uedge old_val0 = INV_SUBWORD(target[start_elem], start_bit, uedge_bits); + hive_uedge old_val0 = inv_subword(target[start_elem], start_bit, uedge_bits); target[start_elem] = old_val0 | (src_subword << start_bit); - old_val1 = INV_SUBWORD(target[start_elem + 1], 0, + old_val1 = inv_subword(target[start_elem + 1], 0, subword_width + start_bit - uedge_bits); target[start_elem + 1] = old_val1 | (src_subword >> (uedge_bits - start_bit)); } else { - hive_uedge old_val = INV_SUBWORD(target[start_elem], start_bit, + hive_uedge old_val = inv_subword(target[start_elem], start_bit, start_bit + subword_width); target[start_elem] = old_val | (src_subword << start_bit); diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 726cb7aa4ecd..93789500416f 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -97,9 +97,6 @@ */ #define JPEG_BYTES (16 * 1024 * 1024) -#define STATS_ENABLED(stage) (stage && stage->binary && stage->binary->info && \ - (stage->binary->info->sp.enable.s3a || stage->binary->info->sp.enable.dis)) - struct sh_css my_css; int __printf(1, 0) (*sh_css_printf)(const char *fmt, va_list args) = NULL; @@ -3743,7 +3740,9 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, * The SP will read the params after it got * empty 3a and dis */ - if (STATS_ENABLED(stage)) { + if (stage->binary && stage->binary->info && + (stage->binary->info->sp.enable.s3a || + stage->binary->info->sp.enable.dis)) { /* there is a stage that needs it */ return_err = ia_css_bufq_enqueue_buffer(thread_id, queue_id, diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c index f08564f58242..588f2adab058 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params.c +++ b/drivers/staging/media/atomisp/pci/sh_css_params.c @@ -98,17 +98,27 @@ #include "sh_css_frac.h" #include "ia_css_bufq.h" -#define FPNTBL_BYTES(binary) \ - (sizeof(char) * (binary)->in_frame_info.res.height * \ - (binary)->in_frame_info.padded_width) +static size_t fpntbl_bytes(const struct ia_css_binary *binary) +{ + return array3_size(sizeof(char), + binary->in_frame_info.res.height, + binary->in_frame_info.padded_width); +} -#define SCTBL_BYTES(binary) \ - (sizeof(unsigned short) * (binary)->sctbl_height * \ - (binary)->sctbl_aligned_width_per_color * IA_CSS_SC_NUM_COLORS) +static size_t sctbl_bytes(const struct ia_css_binary *binary) +{ + return size_mul(sizeof(unsigned short), + array3_size(binary->sctbl_height, + binary->sctbl_aligned_width_per_color, + IA_CSS_SC_NUM_COLORS)); +} -#define MORPH_PLANE_BYTES(binary) \ - (SH_CSS_MORPH_TABLE_ELEM_BYTES * (binary)->morph_tbl_aligned_width * \ - (binary)->morph_tbl_height) +static size_t morph_plane_bytes(const struct ia_css_binary *binary) +{ + return array3_size(SH_CSS_MORPH_TABLE_ELEM_BYTES, + binary->morph_tbl_aligned_width, + binary->morph_tbl_height); +} /* We keep a second copy of the ptr struct for the SP to access. Again, this would not be necessary on the chip. */ @@ -3279,7 +3289,7 @@ sh_css_params_write_to_ddr_internal( if (binary->info->sp.enable.fpnr) { buff_realloced = reallocate_buffer(&ddr_map->fpn_tbl, &ddr_map_size->fpn_tbl, - (size_t)(FPNTBL_BYTES(binary)), + fpntbl_bytes(binary), params->config_changed[IA_CSS_FPN_ID], &err); if (err) { @@ -3304,7 +3314,7 @@ sh_css_params_write_to_ddr_internal( buff_realloced = reallocate_buffer(&ddr_map->sc_tbl, &ddr_map_size->sc_tbl, - SCTBL_BYTES(binary), + sctbl_bytes(binary), params->sc_table_changed, &err); if (err) { @@ -3538,8 +3548,7 @@ sh_css_params_write_to_ddr_internal( buff_realloced |= reallocate_buffer(virt_addr_tetra_x[i], virt_size_tetra_x[i], - (size_t) - (MORPH_PLANE_BYTES(binary)), + morph_plane_bytes(binary), params->morph_table_changed, &err); if (err) { @@ -3549,8 +3558,7 @@ sh_css_params_write_to_ddr_internal( buff_realloced |= reallocate_buffer(virt_addr_tetra_y[i], virt_size_tetra_y[i], - (size_t) - (MORPH_PLANE_BYTES(binary)), + morph_plane_bytes(binary), params->morph_table_changed, &err); if (err) { |