#include #include #include #include #include #include #include #include #include #include //#include #include "vi_pre.h" #include "vi_pre_ioctl.h" #define check_retval(x)\ do {\ if ((x))\ return -EIO;\ } while (0) #define img_buf 0xf0000000 typedef struct { u32 dma_ctl0; u32 dma_ctl1; u32 dma_ctl2; u32 dma_ctl3; u32 dma_ctl4; u32 dma_ctl5; u32 dma_ctl6; u32 dma_ctl7; u32 dma_ctl8; u32 dma_ctl9; u32 dma_ctl10; u32 dma_ctl11; u32 dma_ctl12; u32 dma_ctl13; u32 dma_ctl14; u32 dma_ctl15; u32 dma_ctl16; u32 dma_ctl17; u32 dma_ctl18; u32 dma_ctl19; u32 dma_ctl20; u32 dma_ctl21; u32 dma_ctl22; u32 dma_ctl23; u32 dma_ctl24; u32 dma_ctl25; u32 dma_ctl26; u32 dma_ctl27; u32 dma_ctl28; u32 dma_ctl29; u32 dma_ctl30; u32 dma_ctl31; u32 dma_ctl32; u32 dma_ctl33; u32 dma_ctl34; u32 dma_ctl35; u32 dma_ctl36; u32 dma_ctl37; u32 dma_ctl38; u32 dma_ctl39; u32 dma_ctl40; u32 dma_ctl41; u32 dma_ctl42; u32 dma_ctl43; u32 dma_ctl44; u32 dma_ctl45; u32 dma_ctl46; u32 dma_ctl47; u32 dma_ctl48; u32 dma_ctl49; u32 dma_ctl50; u32 dma_ctl51; } vi_dma_reg_t; static vi_dma_reg_t dma_reg = { .dma_ctl0 = 0x198, .dma_ctl1 = 0x19c, .dma_ctl2 = 0x1a0, .dma_ctl3 = 0x1a4, .dma_ctl4 = 0x1a8, .dma_ctl5 = 0x1ac, .dma_ctl6 = 0x1b0, .dma_ctl7 = 0x1b4, .dma_ctl8 = 0x1b8, .dma_ctl9 = 0x1bc, .dma_ctl10 = 0x1c0, .dma_ctl11 = 0x1c4, .dma_ctl12 = 0x1c8, .dma_ctl13 = 0x1cc, .dma_ctl14 = 0x1d0, .dma_ctl15 = 0x1d4, .dma_ctl16 = 0x1d8, .dma_ctl17 = 0x1dc, .dma_ctl18 = 0x1e0, .dma_ctl19 = 0x1e4, .dma_ctl20 = 0x1e8, .dma_ctl21 = 0x1ec, .dma_ctl22 = 0x1f0, .dma_ctl23 = 0x1f4, .dma_ctl24 = 0x1f8, .dma_ctl25 = 0x1fc, .dma_ctl26 = 0x200, .dma_ctl27 = 0x204, .dma_ctl28 = 0x208, .dma_ctl29 = 0x20c, .dma_ctl30 = 0x210, .dma_ctl31 = 0x214, .dma_ctl32 = 0x218, .dma_ctl33 = 0x21c, .dma_ctl34 = 0x220, .dma_ctl35 = 0x224, .dma_ctl36 = 0x228, .dma_ctl37 = 0x22c, .dma_ctl38 = 0x230, .dma_ctl39 = 0x234, .dma_ctl40 = 0x238, .dma_ctl41 = 0x23c, .dma_ctl42 = 0x240, .dma_ctl43 = 0x244, .dma_ctl44 = 0x248, .dma_ctl45 = 0x24c, .dma_ctl46 = 0x250, .dma_ctl47 = 0x254, .dma_ctl48 = 0x258, .dma_ctl49 = 0x25c, .dma_ctl50 = 0x260, .dma_ctl51 = 0x264, }; static inline void vi_pre_dma_write(struct vi_pre_dev *dev, u32 address, u32 data) { writel(data, dev->reg_base + address); } static inline u32 vi_pre_dma_read(struct vi_pre_dev *dev, u32 address) { return readl(dev->reg_base + address); } static void set_dma_mode(struct vi_pre_dev *dev, vi_pre_dma_mode_t mode) { u32 reg_val = vi_pre_dma_read(dev, dma_reg.dma_ctl0); if(mode == VI_PRE_M_FRAME) { reg_val &= ~1; } else { reg_val |= 1; } vi_pre_dma_write(dev, dma_reg.dma_ctl0, reg_val); } static void set_frame_num(struct vi_pre_dev *dev, u32 num) { u32 reg_val = vi_pre_dma_read(dev, dma_reg.dma_ctl0); num -= 1; reg_val &= ~(3 << 1); reg_val |= (num << 1); vi_pre_dma_write(dev, dma_reg.dma_ctl0, reg_val); } static int get_frame_num(struct vi_pre_dev *dev) { u32 reg_val = vi_pre_dma_read(dev, dma_reg.dma_ctl0); reg_val &= (3 << 2); return (reg_val >> 2) + 1; } /*big align ro little align*/ static void set_bit_mode(struct vi_pre_dev *dev, bool is_big) { u32 reg_val = vi_pre_dma_read(dev, dma_reg.dma_ctl0); if (is_big) { reg_val |= (1 << 3); } else { reg_val &= ~(1 << 3); } vi_pre_dma_write(dev, dma_reg.dma_ctl0, reg_val); } static void set_dma_data_width(struct vi_pre_dev *dev, vi_pre_data_width_t width) { u32 reg_val = vi_pre_dma_read(dev, dma_reg.dma_ctl0); reg_val &= ~(0x7 <<4); reg_val |= (width << 4); vi_pre_dma_write(dev, dma_reg.dma_ctl0, reg_val); } /*length is 4, 8, 16*/ static void set_dma_burst_length(struct vi_pre_dev *dev, u8 len) { u32 reg_val = vi_pre_dma_read(dev, dma_reg.dma_ctl1); len -=1; reg_val &= ~(0xff << 16); reg_val |= (len << 16); reg_val |= 0x3ff; vi_pre_dma_write(dev, dma_reg.dma_ctl1, reg_val); } static u32 read_dma_burst_length(struct vi_pre_dev *dev) { u32 reg_val = vi_pre_dma_read(dev, dma_reg.dma_ctl1); return ((reg_val >> 16) & 0xff) + 1; } static void set_dma_resolution(struct vi_pre_dev *dev, u16 h, u16 v) { u32 reg_val = 0; h &= 0x1fff; v &= 0x1fff; reg_val = h | (v << 16); vi_pre_dma_write(dev, dma_reg.dma_ctl3, reg_val); } static int set_nline_oneline_size(struct vi_pre_dev *dev, vi_pre_dma_cfg_t *cfg) { u32 reg_val = 0; u32 stream_min = 0; u32 cnt_128 = 0; u32 read_num = 0; u32 burstrem = 0; stream_min = cfg->resolution_h; if (cfg->width == VI_PRE_RAW_12BIT || cfg->width == VI_PRE_RAW_10BIT_16ALIGN) { stream_min = cfg->resolution_h * 2; } if (stream_min > cfg->line_size) { return -1; } if (stream_min % 16) { stream_min += 16 - (stream_min % 16); } cnt_128 = stream_min / 16; read_num = cnt_128 / read_dma_burst_length(dev); burstrem = cnt_128 % read_dma_burst_length(dev); if (cnt_128 % read_dma_burst_length(dev)) { read_num +=1; } if (burstrem == 0) { burstrem = read_dma_burst_length(dev); } reg_val = cnt_128 | (read_num << 16) | (burstrem << 27); vi_pre_dma_write(dev, dma_reg.dma_ctl4, reg_val); vi_pre_dma_write(dev, dma_reg.dma_ctl6, cfg->line_size); return 0; } static void set_nline_period(struct vi_pre_dev *dev, u32 num) { u32 reg_val = vi_pre_dma_read(dev, dma_reg.dma_ctl5); reg_val &= ~0xfff; reg_val |= num; printk("vipre nline period num %d, reg_val 0x%x\n", num, reg_val); vi_pre_dma_write(dev, dma_reg.dma_ctl5, reg_val); } static void set_nline_int_period(struct vi_pre_dev *dev, u32 num) { u32 reg_val = vi_pre_dma_read(dev, dma_reg.dma_ctl5); reg_val &= ~(0x7ff << 16); reg_val |= (num << 16); printk("vipre nline int period num %d, reg_val 0x%x\n", num, reg_val); vi_pre_dma_write(dev, dma_reg.dma_ctl5, reg_val); } static u16 get_nline_period(struct vi_pre_dev *dev) { u32 reg_val = vi_pre_dma_read(dev, dma_reg.dma_ctl5); return reg_val & 0xfff; } static u16 get_nline_int_period(struct vi_pre_dev *dev) { u32 reg_val = vi_pre_dma_read(dev, dma_reg.dma_ctl5); return (reg_val >> 16) & 0xfff; } static int set_mfram_oneline_range(struct vi_pre_dev *dev, int frame_id, u32 size) { u32 aligned = 0; u32 reg_val = 0; u32 reg = 0; aligned = read_dma_burst_length(dev) * 16; /*set buf addr*/ if(size % aligned) { printk("<0>""###########error !!!!!!!!! %s, %d\n", __func__, __LINE__); return -1; } reg = frame_id / 2 * 4 + dma_reg.dma_ctl7; reg_val = vi_pre_dma_read(dev, reg); if (frame_id % 2 == 0) { reg_val &= ~(0xffff << 16); reg_val |= (size << 16); } else { reg_val &= ~0xffff; reg_val |= size; } vi_pre_dma_write(dev, reg, reg_val); return 0; } static int set_mframe_oneline_group(struct vi_pre_dev *dev, vi_pre_dma_cfg_t *cfg) { u32 reg_val = 0; u32 stream_min = 0; u32 cnt_128 = 0; u32 read_num = 0; u32 burstrem = 0; stream_min = cfg->resolution_h; if (cfg->width == VI_PRE_RAW_12BIT || cfg->width == VI_PRE_RAW_10BIT_16ALIGN) { stream_min = cfg->resolution_h * 2; } if (stream_min > cfg->line_size) { return -1; } if (stream_min % 16) { stream_min += 16 - (stream_min % 16); } cnt_128 = stream_min / 16; read_num = cnt_128 / read_dma_burst_length(dev); burstrem = cnt_128 % read_dma_burst_length(dev); if (cnt_128 % read_dma_burst_length(dev)) { read_num +=1; } if (burstrem == 0) { burstrem = read_dma_burst_length(dev); } reg_val = cnt_128 | (read_num << 16) | (burstrem << 27); vi_pre_dma_write(dev, dma_reg.dma_ctl4, reg_val); return 0; } static void dma_reset(struct vi_pre_dev *dev) { vi_pre_dma_write(dev, dma_reg.dma_ctl9, 1); while(vi_pre_dma_read(dev, dma_reg.dma_ctl9) == 1); } static void dma_enable(struct vi_pre_dev *dev, int en) { if(en) { vi_pre_dma_write(dev, dma_reg.dma_ctl10, 1); pr_info("%s, %d, dma start\n", __func__, __LINE__); } else { vi_pre_dma_write(dev, dma_reg.dma_ctl10, 0); pr_info("%s, %d, dma stop\n", __func__, __LINE__); } } static void dma_period_clear(struct vi_pre_dev *dev, int ch) { u32 reg_val = vi_pre_dma_read(dev, dma_reg.dma_ctl11); if (reg_val & (1 << ch)) { reg_val &= ~(1 << ch); } else { reg_val |= (1 << ch); } vi_pre_dma_write(dev, dma_reg.dma_ctl11, reg_val); } static void nline_mode_set_line_position(struct vi_pre_dev *dev, int ch, int p) { u32 reg = dma_reg.dma_ctl12 + ch * 4; vi_pre_dma_write(dev, reg, p); } static void nline_mode_set_start_addr(struct vi_pre_dev *dev, int ch, unsigned long addr) { u32 reg = dma_reg.dma_ctl15 + ch * 8; u8 h = addr >> 32; u32 l = addr & 0xffffffff; vi_pre_dma_write(dev, reg, h); vi_pre_dma_write(dev, reg + 4, l); } static u16 nline_mode_period_cnt(struct vi_pre_dev *dev, int ch) { u32 reg = dma_reg.dma_ctl21 + ch / 2 * 4; if(ch % 2) { return (vi_pre_dma_read(dev, reg) >> 16) & 0xfff; } else { return vi_pre_dma_read(dev, reg) & 0xfff; } } static void mframe_mode_set_position(struct vi_pre_dev *dev, int vc_ch, int f, int l) { u32 reg = dma_reg.dma_ctl23 + vc_ch / 2 * 4; u32 reg_val = vi_pre_dma_read(dev, reg); f &= 3; l &= 0xfff; if (vc_ch % 2) { reg_val &=~(0xffff << 16); reg_val |= (l << 16) | (f << 29); } else { reg_val &=~0xffff; reg_val |= l | (f << 13); } vi_pre_dma_write(dev, reg, reg_val); } static void mframe_set_start_addr(struct vi_pre_dev *dev, int frame_id, int vc_ch, unsigned long addr) { u32 reg = 0; u8 h = addr >> 32; u32 l = addr & 0xffffffff; if (frame_id <= 2) { reg = dma_reg.dma_ctl25 + frame_id * 24 + vc_ch * 8; } else { reg = dma_reg.dma_ctl45 + vc_ch * 8; } vi_pre_dma_write(dev, reg, h); vi_pre_dma_write(dev, reg + 4, l); } static u32 mframe_frame_done_flag(struct vi_pre_dev *dev) { return vi_pre_dma_read(dev, dma_reg.dma_ctl43); } static void mframe_frame_done_flag_clear(struct vi_pre_dev *dev, u32 mask) { vi_pre_dma_write(dev, dma_reg.dma_ctl43, mask); } static void dma_interrupt_set(struct vi_pre_dev *dev, u32 mask, int en) { u32 reg_val = vi_pre_dma_read(dev, dma_reg.dma_ctl44); if (en) { reg_val &= ~(mask << 16); } else { reg_val |= (mask << 16); } vi_pre_dma_write(dev, dma_reg.dma_ctl44, reg_val); reg_val = vi_pre_dma_read(dev, dma_reg.dma_ctl44); } static u16 dma_interrupt_status(struct vi_pre_dev *dev) { return vi_pre_dma_read(dev, dma_reg.dma_ctl44) & 0xffff; } static void dma_clear_interrupt_status(struct vi_pre_dev *dev, u32 sta) { u32 reg = vi_pre_dma_read(dev, dma_reg.dma_ctl44); reg |= sta; return vi_pre_dma_write(dev, dma_reg.dma_ctl44, reg); } static int vi_pre_mframe_config(struct vi_pre_dev *dev, vi_pre_dma_cfg_t *cfg) { unsigned long buf_base = (unsigned long)cfg->buf; int ret = 0; int i = 0; int j = 0; if (cfg->num > 4) { printk("%s, %d, cfg frame num error!!!\n", __func__, __LINE__); return -1; } if (cfg->buf_size < cfg->line_size * cfg->resolution_v * cfg->num) { printk("%s, %d, vipre buf size error!!!\n", __func__, __LINE__); return -1; } set_frame_num(dev, cfg->num); ret = set_mframe_oneline_group(dev, cfg); if (ret != 0) { printk("<0>""!!!!!!!set mframe oneline size error!!!!!!!!!!!!!!!!\n"); return -1; } for(i = 0; i < cfg->num; i++) { ret = set_mfram_oneline_range(dev, i, cfg->line_size); if (ret != 0) { printk("<0>""!!!!!!!set mframe oneline range error!!!!!!!!!!!!!!!!\n"); return -1; } for (j = 0; j < cfg->vc_num; j++) { mframe_set_start_addr(dev, i, j, buf_base); buf_base += cfg->line_size * cfg->resolution_v; } } return 0; } static int vi_pre_nline_config(struct vi_pre_dev *dev, vi_pre_dma_cfg_t *cfg) { unsigned long buf_base = (unsigned long)cfg->buf; int i = 0; if (cfg->line_size % 256) { return -1; } if (cfg->buf_size < cfg->line_size * cfg->num) { return -1; } if (set_nline_oneline_size(dev, cfg) != 0) { return -1; } set_nline_period(dev, cfg->num); set_nline_int_period(dev, cfg->n_line_int); for(i = 0; i < cfg->vc_num; i++) { nline_mode_set_start_addr(dev, i, buf_base); buf_base += cfg->line_size * cfg->resolution_v; } return 0; } int vi_pre_dma_init(struct vi_pre_dev *pdriver_dev) { return 0; } int vi_pre_dma_uninit(struct platform_device *pdev) { struct vi_pre_dev *pdriver_dev; pdriver_dev = platform_get_drvdata(pdev); memset(pdriver_dev->cnt, 0, sizeof(pdriver_dev->cnt)); return 0; } static int dma_config(struct vi_pre_dev *pdriver_dev, vi_pre_dma_cfg_t *cfg) { int ret = 0; set_dma_burst_length(pdriver_dev, 16); set_dma_data_width(pdriver_dev, cfg->width); set_bit_mode(pdriver_dev, 0); set_dma_mode(pdriver_dev, cfg->mode); set_dma_resolution(pdriver_dev, cfg->resolution_h, cfg->resolution_v); if (cfg->mode == VI_PRE_M_FRAME) { ret = vi_pre_mframe_config(pdriver_dev, cfg); pdriver_dev->is_mframe_mode = true; } else if (cfg->mode == VI_PRE_N_LANE) { ret = vi_pre_nline_config(pdriver_dev, cfg); pdriver_dev->is_mframe_mode = false; } return ret; } int vi_pre_dma_config(struct vi_pre_dev *pdriver_dev, void *arg) { vi_pre_dma_cfg_t cfg; check_retval(copy_from_user(&cfg, arg, sizeof(cfg))); //cfg.buf_size = cfg.num * cfg.vc_num * cfg.line_size * cfg.resolution_v; //cfg.buf = (u8 *)img_buf; return dma_config(pdriver_dev, &cfg); } int vi_pre_dma_mframe_set_buf(struct vi_pre_dev *pdriver_dev, void *arg) { int j = 0; vi_pre_mframe_cfg_t mframe_cfg; check_retval(copy_from_user(&mframe_cfg, arg, sizeof(mframe_cfg))); unsigned long buf_base = (unsigned long)mframe_cfg.buf_addr; for (j = 0; j < mframe_cfg.vc_num; j++) { mframe_set_start_addr(pdriver_dev, mframe_cfg.frame_id, j, buf_base); buf_base += mframe_cfg.frame_size; } return 0; } int vi_pre_dma_get_mframe_done_id(struct vi_pre_dev *pdriver_dev, void *arg) { vi_pre_update_frame_info_t info; info.update_frame_id = pdriver_dev->update_frame_id; info.update_vc_id = pdriver_dev->update_vc_id; check_retval(copy_to_user(arg, &info,sizeof(info))); return 0; } int vi_pre_dma_mframe_update_buf(struct vi_pre_dev *pdriver_dev, void *arg) { vi_pre_mframe_update_t mframe; check_retval(copy_from_user(&mframe, arg, sizeof(mframe))); unsigned long buf_base = (unsigned long)mframe.buf_addr; mframe_set_start_addr(pdriver_dev, mframe.frame_id, mframe.vc_id, buf_base); return 0; } int vi_pre_dma_start(struct vi_pre_dev *pdriver_dev) { u32 mask = VIPRE_BUS_ERR | VIPRE_FIFO_OVER | VIPRE_NMOVERFLOW; if (pdriver_dev->is_mframe_mode) { mask |= VIPRE_FRAME_DONE; } else { mask |= VIPRE_LINE_DONE; } dma_interrupt_set(pdriver_dev, mask, 1); dma_enable(pdriver_dev, 1); return 0; } int vi_pre_dma_stop(struct vi_pre_dev *pdriver_dev) { u32 mask = VIPRE_BUS_ERR | VIPRE_FIFO_OVER | VIPRE_NMOVERFLOW; dma_interrupt_set(pdriver_dev, mask, 0); dma_enable(pdriver_dev, 0); udelay(1000); return 0; } static int vipre_event = 0; int *vi_pre_event(void) { return &vipre_event; } static int f_done_sta_to_frame_id(u32 sta) { #define FRAME_0_DONE (1 << 11) #define FRAME_1_DONE (1 << 10) #define FRAME_2_DONE (1 << 9) #define FRAME_3_DONE (1 << 8) int f_id = 0; if (sta & FRAME_0_DONE) { f_id = 3; } else if (sta & FRAME_1_DONE) { f_id = 0; } else if (sta & FRAME_2_DONE) { f_id = 1; } else if (sta & FRAME_3_DONE) { f_id = 2; } return f_id; } void vi_pre_dma_interrupt_handler(struct vi_pre_dev *pdriver_dev) { u32 status = 0; u32 f_done_sta = 0; unsigned long flags = 0; //int i = 0; spin_lock_irqsave(&pdriver_dev->slock, flags); status = dma_interrupt_status(pdriver_dev); if (status & (1 << 4)) { printk("<0>""vipre err int sta 0x%x\n", status); } dma_clear_interrupt_status(pdriver_dev, status); if (status & VIPRE_FRAME_DONE) { pdriver_dev->cnt++; if (pdriver_dev->cnt >= 4) { pdriver_dev->cnt = 0; } vipre_event = 1; f_done_sta = mframe_frame_done_flag(pdriver_dev); mframe_frame_done_flag_clear(pdriver_dev, f_done_sta); pdriver_dev->update_frame_id = f_done_sta_to_frame_id(f_done_sta); mframe_mode_set_position(pdriver_dev, 0, pdriver_dev->update_frame_id, 0); pdriver_dev->update_vc_id = 0; } else if (status & VIPRE_LINE_DONE) { //u32 nline_done_sta =; //pdriver_dev->cnt++; //printk("line done %x\n", f_done_sta); //vipre_event = 1; } #if 0 //u32 line_cnt = pdriver_dev->cnt * get_nline_int_period(pdriver_dev); if (pdriver_dev->is_mframe_mode) { for(i = 0; i < 3; i++) { if(pdriver_dev->cnt[i] < get_frame_num(pdriver_dev)) { continue; } pdriver_dev->cnt[i] = 0; dma_period_clear(pdriver_dev, i); } } else (pdriver_dev->is_mframe_mode == 0 && line_cnt >= get_nline_period(pdriver_dev)){ dma_period_clear(struct vi_pre_dev *dev, int ch) } #endif spin_unlock_irqrestore(&pdriver_dev->slock, flags); } int vi_pore_vc_bind(struct platform_device *pdev, u8 buf_id, u8 vc_id) { return 0; } int vi_pore_attach_callback(struct platform_device *pdev) { return 0; } int vi_pore_deattach_callback(struct platform_device *pdev) { return 0; } /////////////////demo/////////////////////// void test(struct vi_pre_dev *pdev) { vi_pre_dma_cfg_t cfg; cfg.vc_num = 1; cfg.width = VI_PRE_RAW_12BIT; cfg.mode = VI_PRE_M_FRAME; cfg.resolution_h = 1944; //1920;//3840; cfg.resolution_v = 1100; //1080;//2160; cfg.line_size = 2048 * 2; //必须256byte对齐 cfg.num = 4; //n line num, or m frame num(m frme max is 4) cfg.buf_size = 2048 * 1100 * 2 * 10; cfg.buf = (u8 *)img_buf; dma_config(pdev, &cfg); vi_pre_dma_start(pdev); }