/* * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver * * Copyright (C) 2013 Samsung Electronics Co., Ltd. * * Authors: Younghwan Joo <yhwan.joo@samsung.com> * Sylwester Nawrocki <s.nawrocki@samsung.com> * * 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. */ #ifndef FIMC_IS_H_ #define FIMC_IS_H_ #include <asm/barrier.h> #include <linux/clk.h> #include <linux/device.h> #include <linux/kernel.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/sizes.h> #include <linux/spinlock.h> #include <linux/types.h> #include <media/videobuf2-core.h> #include <media/v4l2-ctrls.h> #include "fimc-isp.h" #include "fimc-is-command.h" #include "fimc-is-sensor.h" #include "fimc-is-param.h" #include "fimc-is-regs.h" #define FIMC_IS_DRV_NAME "exynos4-fimc-is" #define FIMC_IS_FW_FILENAME "fimc_is_fw.bin" #define FIMC_IS_SETFILE_6A3 "setfile.bin" #define FIMC_IS_FW_LOAD_TIMEOUT 1000 /* ms */ #define FIMC_IS_POWER_ON_TIMEOUT 1000 /* us */ #define FIMC_IS_SENSOR_NUM 2 /* Memory definitions */ #define FIMC_IS_CPU_MEM_SIZE (0xa00000) #define FIMC_IS_CPU_BASE_MASK ((1 << 26) - 1) #define FIMC_IS_REGION_SIZE 0x5000 #define FIMC_IS_DEBUG_REGION_OFFSET 0x0084b000 #define FIMC_IS_SHARED_REGION_OFFSET 0x008c0000 #define FIMC_IS_FW_INFO_LEN 31 #define FIMC_IS_FW_VER_LEN 7 #define FIMC_IS_FW_DESC_LEN (FIMC_IS_FW_INFO_LEN + \ FIMC_IS_FW_VER_LEN) #define FIMC_IS_SETFILE_INFO_LEN 39 #define FIMC_IS_EXTRA_MEM_SIZE (FIMC_IS_EXTRA_FW_SIZE + \ FIMC_IS_EXTRA_SETFILE_SIZE + 0x1000) #define FIMC_IS_EXTRA_FW_SIZE 0x180000 #define FIMC_IS_EXTRA_SETFILE_SIZE 0x4b000 /* TODO: revisit */ #define FIMC_IS_FW_ADDR_MASK ((1 << 26) - 1) #define FIMC_IS_FW_SIZE_MAX (SZ_4M) #define FIMC_IS_FW_SIZE_MIN (SZ_32K) #define ATCLK_MCUISP_FREQUENCY 100000000UL #define ACLK_AXI_FREQUENCY 100000000UL enum { ISS_CLK_PPMUISPX, ISS_CLK_PPMUISPMX, ISS_CLK_LITE0, ISS_CLK_LITE1, ISS_CLK_MPLL, ISS_CLK_ISP, ISS_CLK_DRC, ISS_CLK_FD, ISS_CLK_MCUISP, ISS_CLK_UART, ISS_GATE_CLKS_MAX, ISS_CLK_ISP_DIV0 = ISS_GATE_CLKS_MAX, ISS_CLK_ISP_DIV1, ISS_CLK_MCUISP_DIV0, ISS_CLK_MCUISP_DIV1, ISS_CLK_ACLK200, ISS_CLK_ACLK200_DIV, ISS_CLK_ACLK400MCUISP, ISS_CLK_ACLK400MCUISP_DIV, ISS_CLKS_MAX }; /* The driver's internal state flags */ enum { IS_ST_IDLE, IS_ST_PWR_ON, IS_ST_A5_PWR_ON, IS_ST_FW_LOADED, IS_ST_OPEN_SENSOR, IS_ST_SETFILE_LOADED, IS_ST_INIT_DONE, IS_ST_STREAM_ON, IS_ST_STREAM_OFF, IS_ST_CHANGE_MODE, IS_ST_BLOCK_CMD_CLEARED, IS_ST_SET_ZOOM, IS_ST_PWR_SUBIP_ON, IS_ST_END, }; enum af_state { FIMC_IS_AF_IDLE = 0, FIMC_IS_AF_SETCONFIG = 1, FIMC_IS_AF_RUNNING = 2, FIMC_IS_AF_LOCK = 3, FIMC_IS_AF_ABORT = 4, FIMC_IS_AF_FAILED = 5, }; enum af_lock_state { FIMC_IS_AF_UNLOCKED = 0, FIMC_IS_AF_LOCKED = 2 }; enum ae_lock_state { FIMC_IS_AE_UNLOCKED = 0, FIMC_IS_AE_LOCKED = 1 }; enum awb_lock_state { FIMC_IS_AWB_UNLOCKED = 0, FIMC_IS_AWB_LOCKED = 1 }; enum { IS_METERING_CONFIG_CMD, IS_METERING_CONFIG_WIN_POS_X, IS_METERING_CONFIG_WIN_POS_Y, IS_METERING_CONFIG_WIN_WIDTH, IS_METERING_CONFIG_WIN_HEIGHT, IS_METERING_CONFIG_MAX }; struct is_setfile { const struct firmware *info; int state; u32 sub_index; u32 base; size_t size; }; struct is_fd_result_header { u32 offset; u32 count; u32 index; u32 curr_index; u32 width; u32 height; }; struct is_af_info { u16 mode; u32 af_state; u32 af_lock_state; u32 ae_lock_state; u32 awb_lock_state; u16 pos_x; u16 pos_y; u16 prev_pos_x; u16 prev_pos_y; u16 use_af; }; struct fimc_is_firmware { const struct firmware *f_w; dma_addr_t paddr; void *vaddr; unsigned int size; char info[FIMC_IS_FW_INFO_LEN + 1]; char version[FIMC_IS_FW_VER_LEN + 1]; char setfile_info[FIMC_IS_SETFILE_INFO_LEN + 1]; u8 state; }; struct fimc_is_memory { /* physical base address */ dma_addr_t paddr; /* virtual base address */ void *vaddr; /* total length */ unsigned int size; }; #define FIMC_IS_I2H_MAX_ARGS 12 struct i2h_cmd { u32 cmd; u32 sensor_id; u16 num_args; u32 args[FIMC_IS_I2H_MAX_ARGS]; }; struct h2i_cmd { u16 cmd_type; u32 entry_id; }; #define FIMC_IS_DEBUG_MSG 0x3f #define FIMC_IS_DEBUG_LEVEL 3 struct fimc_is_setfile { const struct firmware *info; unsigned int state; unsigned int size; u32 sub_index; u32 base; }; struct chain_config { struct global_param global; struct sensor_param sensor; struct isp_param isp; struct drc_param drc; struct fd_param fd; unsigned long p_region_index1; unsigned long p_region_index2; }; /** * struct fimc_is - fimc-is data structure * @pdev: pointer to FIMC-IS platform device * @pctrl: pointer to pinctrl structure for this device * @v4l2_dev: pointer to top the level v4l2_device * @alloc_ctx: videobuf2 memory allocator context * @lock: mutex serializing video device and the subdev operations * @slock: spinlock protecting this data structure and the hw registers * @clocks: FIMC-LITE gate clock * @regs: MCUCTL mmapped registers region * @pmu_regs: PMU ISP mmapped registers region * @irq_queue: interrupt handling waitqueue * @lpm: low power mode flag * @state: internal driver's state flags */ struct fimc_is { struct platform_device *pdev; struct pinctrl *pctrl; struct v4l2_device *v4l2_dev; struct fimc_is_firmware fw; struct fimc_is_memory memory; struct firmware *f_w; struct fimc_isp isp; struct fimc_is_sensor *sensor; struct fimc_is_setfile setfile; struct vb2_alloc_ctx *alloc_ctx; struct v4l2_ctrl_handler ctrl_handler; struct mutex lock; spinlock_t slock; struct clk *clocks[ISS_CLKS_MAX]; void __iomem *regs; void __iomem *pmu_regs; int irq; wait_queue_head_t irq_queue; u8 lpm; unsigned long state; unsigned int sensor_index; struct i2h_cmd i2h_cmd; struct h2i_cmd h2i_cmd; struct is_fd_result_header fd_header; struct chain_config config[IS_SC_MAX]; unsigned config_index; struct is_region *is_p_region; dma_addr_t is_dma_p_region; struct is_share_region *is_shared_region; struct is_af_info af; struct dentry *debugfs_entry; }; static inline struct fimc_is *fimc_isp_to_is(struct fimc_isp *isp) { return container_of(isp, struct fimc_is, isp); } static inline void fimc_is_mem_barrier(void) { mb(); } static inline void fimc_is_set_param_bit(struct fimc_is *is, int num) { struct chain_config *cfg = &is->config[is->config_index]; if (num >= 32) set_bit(num - 32, &cfg->p_region_index2); else set_bit(num, &cfg->p_region_index1); } static inline void fimc_is_set_param_ctrl_cmd(struct fimc_is *is, int cmd) { is->is_p_region->parameter.isp.control.cmd = cmd; } static inline void mcuctl_write(u32 v, struct fimc_is *is, unsigned int offset) { writel(v, is->regs + offset); } static inline u32 mcuctl_read(struct fimc_is *is, unsigned int offset) { return readl(is->regs + offset); } static inline void pmuisp_write(u32 v, struct fimc_is *is, unsigned int offset) { writel(v, is->pmu_regs + offset); } static inline u32 pmuisp_read(struct fimc_is *is, unsigned int offset) { return readl(is->pmu_regs + offset); } int fimc_is_wait_event(struct fimc_is *is, unsigned long bit, unsigned int state, unsigned int timeout); int fimc_is_cpu_set_power(struct fimc_is *is, int on); int fimc_is_start_firmware(struct fimc_is *is); int fimc_is_hw_initialize(struct fimc_is *is); void fimc_is_log_dump(const char *level, const void *buf, size_t len); #endif /* FIMC_IS_H_ */