1/* 2 * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver 3 * 4 * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd. 5 * 6 * Authors: Younghwan Joo <yhwan.joo@samsung.com> 7 * Sylwester Nawrocki <s.nawrocki@samsung.com> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13#include <linux/delay.h> 14 15#include "fimc-is.h" 16#include "fimc-is-command.h" 17#include "fimc-is-regs.h" 18#include "fimc-is-sensor.h" 19 20void fimc_is_fw_clear_irq1(struct fimc_is *is, unsigned int nr) 21{ 22 mcuctl_write(1UL << nr, is, MCUCTL_REG_INTCR1); 23} 24 25void fimc_is_fw_clear_irq2(struct fimc_is *is) 26{ 27 u32 cfg = mcuctl_read(is, MCUCTL_REG_INTSR2); 28 mcuctl_write(cfg, is, MCUCTL_REG_INTCR2); 29} 30 31void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is) 32{ 33 mcuctl_write(INTGR0_INTGD(0), is, MCUCTL_REG_INTGR0); 34} 35 36int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is) 37{ 38 unsigned int timeout = 2000; 39 u32 cfg, status; 40 41 do { 42 cfg = mcuctl_read(is, MCUCTL_REG_INTMSR0); 43 status = INTMSR0_GET_INTMSD(0, cfg); 44 45 if (--timeout == 0) { 46 dev_warn(&is->pdev->dev, "%s timeout\n", 47 __func__); 48 return -ETIMEDOUT; 49 } 50 udelay(1); 51 } while (status != 0); 52 53 return 0; 54} 55 56int fimc_is_hw_set_param(struct fimc_is *is) 57{ 58 struct chain_config *config = &is->config[is->config_index]; 59 unsigned int param_count = __get_pending_param_count(is); 60 61 fimc_is_hw_wait_intmsr0_intmsd0(is); 62 63 mcuctl_write(HIC_SET_PARAMETER, is, MCUCTL_REG_ISSR(0)); 64 mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); 65 mcuctl_write(is->config_index, is, MCUCTL_REG_ISSR(2)); 66 67 mcuctl_write(param_count, is, MCUCTL_REG_ISSR(3)); 68 mcuctl_write(config->p_region_index[0], is, MCUCTL_REG_ISSR(4)); 69 mcuctl_write(config->p_region_index[1], is, MCUCTL_REG_ISSR(5)); 70 71 fimc_is_hw_set_intgr0_gd0(is); 72 return 0; 73} 74 75static int __maybe_unused fimc_is_hw_set_tune(struct fimc_is *is) 76{ 77 fimc_is_hw_wait_intmsr0_intmsd0(is); 78 79 mcuctl_write(HIC_SET_TUNE, is, MCUCTL_REG_ISSR(0)); 80 mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); 81 mcuctl_write(is->h2i_cmd.entry_id, is, MCUCTL_REG_ISSR(2)); 82 83 fimc_is_hw_set_intgr0_gd0(is); 84 return 0; 85} 86 87#define FIMC_IS_MAX_PARAMS 4 88 89int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num_args) 90{ 91 int i; 92 93 if (num_args > FIMC_IS_MAX_PARAMS) 94 return -EINVAL; 95 96 is->i2h_cmd.num_args = num_args; 97 98 for (i = 0; i < FIMC_IS_MAX_PARAMS; i++) { 99 if (i < num_args) 100 is->i2h_cmd.args[i] = mcuctl_read(is, 101 MCUCTL_REG_ISSR(12 + i)); 102 else 103 is->i2h_cmd.args[i] = 0; 104 } 105 return 0; 106} 107 108void fimc_is_hw_set_isp_buf_mask(struct fimc_is *is, unsigned int mask) 109{ 110 if (hweight32(mask) == 1) { 111 dev_err(&is->pdev->dev, "%s(): not enough buffers (mask %#x)\n", 112 __func__, mask); 113 return; 114 } 115 116 if (mcuctl_read(is, MCUCTL_REG_ISSR(23)) != 0) 117 dev_dbg(&is->pdev->dev, "non-zero DMA buffer mask\n"); 118 119 mcuctl_write(mask, is, MCUCTL_REG_ISSR(23)); 120} 121 122void fimc_is_hw_set_sensor_num(struct fimc_is *is) 123{ 124 pr_debug("setting sensor index to: %d\n", is->sensor_index); 125 126 mcuctl_write(IH_REPLY_DONE, is, MCUCTL_REG_ISSR(0)); 127 mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); 128 mcuctl_write(IHC_GET_SENSOR_NUM, is, MCUCTL_REG_ISSR(2)); 129 mcuctl_write(FIMC_IS_SENSORS_NUM, is, MCUCTL_REG_ISSR(3)); 130} 131 132void fimc_is_hw_close_sensor(struct fimc_is *is, unsigned int index) 133{ 134 if (is->sensor_index != index) 135 return; 136 137 fimc_is_hw_wait_intmsr0_intmsd0(is); 138 mcuctl_write(HIC_CLOSE_SENSOR, is, MCUCTL_REG_ISSR(0)); 139 mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); 140 mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(2)); 141 fimc_is_hw_set_intgr0_gd0(is); 142} 143 144void fimc_is_hw_get_setfile_addr(struct fimc_is *is) 145{ 146 fimc_is_hw_wait_intmsr0_intmsd0(is); 147 mcuctl_write(HIC_GET_SET_FILE_ADDR, is, MCUCTL_REG_ISSR(0)); 148 mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); 149 fimc_is_hw_set_intgr0_gd0(is); 150} 151 152void fimc_is_hw_load_setfile(struct fimc_is *is) 153{ 154 fimc_is_hw_wait_intmsr0_intmsd0(is); 155 mcuctl_write(HIC_LOAD_SET_FILE, is, MCUCTL_REG_ISSR(0)); 156 mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); 157 fimc_is_hw_set_intgr0_gd0(is); 158} 159 160int fimc_is_hw_change_mode(struct fimc_is *is) 161{ 162 const u8 cmd[] = { 163 HIC_PREVIEW_STILL, HIC_PREVIEW_VIDEO, 164 HIC_CAPTURE_STILL, HIC_CAPTURE_VIDEO, 165 }; 166 167 if (WARN_ON(is->config_index >= ARRAY_SIZE(cmd))) 168 return -EINVAL; 169 170 mcuctl_write(cmd[is->config_index], is, MCUCTL_REG_ISSR(0)); 171 mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); 172 mcuctl_write(is->setfile.sub_index, is, MCUCTL_REG_ISSR(2)); 173 fimc_is_hw_set_intgr0_gd0(is); 174 return 0; 175} 176 177void fimc_is_hw_stream_on(struct fimc_is *is) 178{ 179 fimc_is_hw_wait_intmsr0_intmsd0(is); 180 mcuctl_write(HIC_STREAM_ON, is, MCUCTL_REG_ISSR(0)); 181 mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); 182 mcuctl_write(0, is, MCUCTL_REG_ISSR(2)); 183 fimc_is_hw_set_intgr0_gd0(is); 184} 185 186void fimc_is_hw_stream_off(struct fimc_is *is) 187{ 188 fimc_is_hw_wait_intmsr0_intmsd0(is); 189 mcuctl_write(HIC_STREAM_OFF, is, MCUCTL_REG_ISSR(0)); 190 mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); 191 fimc_is_hw_set_intgr0_gd0(is); 192} 193 194void fimc_is_hw_subip_power_off(struct fimc_is *is) 195{ 196 fimc_is_hw_wait_intmsr0_intmsd0(is); 197 mcuctl_write(HIC_POWER_DOWN, is, MCUCTL_REG_ISSR(0)); 198 mcuctl_write(is->sensor_index, is, MCUCTL_REG_ISSR(1)); 199 fimc_is_hw_set_intgr0_gd0(is); 200} 201 202int fimc_is_itf_s_param(struct fimc_is *is, bool update) 203{ 204 int ret; 205 206 if (update) 207 __is_hw_update_params(is); 208 209 fimc_is_mem_barrier(); 210 211 clear_bit(IS_ST_BLOCK_CMD_CLEARED, &is->state); 212 fimc_is_hw_set_param(is); 213 ret = fimc_is_wait_event(is, IS_ST_BLOCK_CMD_CLEARED, 1, 214 FIMC_IS_CONFIG_TIMEOUT); 215 if (ret < 0) 216 dev_err(&is->pdev->dev, "%s() timeout\n", __func__); 217 218 return ret; 219} 220 221int fimc_is_itf_mode_change(struct fimc_is *is) 222{ 223 int ret; 224 225 clear_bit(IS_ST_CHANGE_MODE, &is->state); 226 fimc_is_hw_change_mode(is); 227 ret = fimc_is_wait_event(is, IS_ST_CHANGE_MODE, 1, 228 FIMC_IS_CONFIG_TIMEOUT); 229 if (ret < 0) 230 dev_err(&is->pdev->dev, "%s(): mode change (%d) timeout\n", 231 __func__, is->config_index); 232 return ret; 233} 234