www.pudn.com > ucosii_core.rar > cim.c, change:2007-07-13,size:8065b


/*
 * ucosii/jz4730/drv/cim.c
 *
 * Camera Interface Module (CIM) driver for JzSOC
 * This driver is independent of the camera sensor
 *
 * Copyright (C) 2005  JunZheng semiconductor
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "includes.h" //ucosii

#include "regs.h"
#include "ops.h"  
#include "clock.h"  //for __cpm_get_sclk()

#include "camera.h" // Select one of the sensors

#ifndef u8
#define u8	unsigned char
#endif

#ifndef u16
#define u16	unsigned short
#endif

#ifndef u32
#define u32	unsigned int
#endif

#ifndef NULL
#define NULL	0
#endif

#define CIM_NAME        "cim"

/*
 * Define the Max Image Size
 */
#define MAX_IMAGE_WIDTH  640
#define MAX_IMAGE_HEIGHT 480
#define MAX_IMAGE_BPP    16  
#define MAX_FRAME_SIZE   (MAX_IMAGE_WIDTH * MAX_IMAGE_HEIGHT * MAX_IMAGE_BPP / 8)

typedef struct
{
	u32 width;
	u32 height;
	u32 bpp;
} img_param_t;

typedef struct
{
	u32 cfg;
	u32 ctrl;
	u32 mclk;
} cim_config_t;

/*
 * CIM configuration.
 */

struct cim_config {
	int mclk;/* Master clock output to the sensor */
	int vsp; /* VSYNC Polarity:0-rising edge is active,1-falling edge is active */
	int hsp; /* HSYNC Polarity:0-rising edge is active,1-falling edge is active */
	int pcp; /* PCLK Polarity:0-rising edge sampling,1-falling edge sampling */
	int dsm; /* Data Sampling Mode:0-CCIR656 Progressive Mode, 1-CCIR656 Interlace Mode,2-Gated Clock Mode,3-Non-Gated Clock Mode */
	int pack; /* Data Packing Mode: suppose received data sequence were 0x11 0x22 0x33 0x44, then packing mode will rearrange the sequence in the RXFIFO:
		     0: 0x11 0x22 0x33 0x44
		     1: 0x22 0x33 0x44 0x11
		     2: 0x33 0x44 0x11 0x22
		     3: 0x44 0x11 0x22 0x33
		     4: 0x44 0x33 0x22 0x11
		     5: 0x33 0x22 0x11 0x44
		     6: 0x22 0x11 0x44 0x33
		     7: 0x11 0x44 0x33 0x22
		  */
	int inv_dat;    /* Inverse Input Data Enable */
	int frc;        /* Frame Rate Control:0-15 */
	int trig;   /* RXFIFO Trigger: 
		       0: 4
		       1: 8
		       2: 12
		       3: 16
		       4: 20
		       5: 24
		       6: 28
		       7: 32
		    */
};

static struct cim_config cim_cfg = {
#ifdef CONFIG_OV7660
        24000000, 1, 0, 0, 2, 2, 0, 0, 1,
#endif
#ifdef CONFIG_KSMOV7649
	24000000, 0, 0, 0, 0, 0, 0, 0, 3,
#endif
#ifdef CONFIG_HV7131
	24000000, 0, 0, 1, 2, 2, 0, 0, 1,
#endif
};

/* Actual image size, must less than max values */
static int img_width = IMG_WIDTH, img_height = IMG_HEIGHT, img_bpp = IMG_BPP;

/*
 * CIM DMA descriptor
 */
struct cim_desc {
	u32 nextdesc;   /* Physical address of next desc */
	u32 framebuf;   /* Physical address of frame buffer */
	u32 frameid;    /* Frame ID */ 
	u32 dmacmd;     /* DMA command */
};

/*
 * CIM device structure
 */
struct cim_device {
	unsigned char *framebuf;
	unsigned int frame_size;
  //	unsigned int page_order;
  //	wait_queue_head_t wait_queue;
        OS_EVENT *WaitSem;
	struct cim_desc frame_desc __attribute__ ((aligned (16)));
};

// global
static struct cim_device *cim_dev;

/*==========================================================================
 * CIM init routines
 *========================================================================*/

static void cim_config(cim_config_t *c)
{
	REG_CIM_CFG = c->cfg;
	REG_CIM_CTRL = c->ctrl;

	// Set the master clock output
	__cim_set_master_clk(__cpm_get_sclk(), c->mclk);

	// Enable sof, eof and stop interrupts
	__cim_enable_sof_intr();
	__cim_enable_eof_intr();
	__cim_enable_stop_intr();
}

/*==========================================================================
 * CIM start/stop operations
 *========================================================================*/

static int cim_start_dma(unsigned char *ubuf)
{
        u8 err;

	__cim_disable();
	//	dma_cache_wback((unsigned long)cim_dev->framebuf, (2 ^ (cim_dev->page_order)) * 4096);
	__dcache_writeback_all();  //?
	// set the desc addr
	__cim_set_da(PHYS(&(cim_dev->frame_desc)));

	__cim_clear_state();	// clear state register
	__cim_reset_rxfifo();	// resetting rxfifo
	__cim_unreset_rxfifo();
	__cim_enable_dma();	// enable dma
	//printf("2cim dam in.\n");
	// start
	__cim_enable();

	// wait for interrupts
	//	interruptible_sleep_on(&cim_dev->wait_queue);
	OSSemPend(cim_dev->WaitSem, OS_TICKS_PER_SEC, &err);
	//printf("3cim dam in.\n");
	// copy frame data to user buffer
	memcpy(ubuf, cim_dev->framebuf, cim_dev->frame_size);

	return cim_dev->frame_size;
}

static void cim_stop(void)
{
	__cim_disable();
	__cim_clear_state();
}

/*==========================================================================
 * Framebuffer allocation and destroy
 *========================================================================*/

static void cim_fb_destroy(void)
{
	if (cim_dev->framebuf) {
	  cim_dev->framebuf = NULL;
	}
}

static int cim_fb_alloc(void)
{
  static u8 cim_heap[IMG_WIDTH * IMG_HEIGHT * IMG_BPP / 8 + 0x10];
  cim_dev->frame_size = img_width * img_height * (img_bpp/8);

	cim_dev->framebuf = (u8 *)(((u32)cim_heap+0x10) & ~0xf);

	if ( !(cim_dev->framebuf) ) {
		return -1;
	}

	cim_dev->frame_desc.nextdesc = PHYS(&(cim_dev->frame_desc));
	cim_dev->frame_desc.framebuf = PHYS(cim_dev->framebuf);
	cim_dev->frame_desc.frameid = 0x52052018;
	cim_dev->frame_desc.dmacmd = CIM_CMD_EOFINT | CIM_CMD_STOP | (cim_dev->frame_size >> 2); // stop after capturing a frame

	//	dma_cache_wback((unsigned long)(&(cim_dev->frame_desc)), 16);
	__dcache_writeback_all();  //?
	return 0;
}

/*==========================================================================
 * File operations
 *========================================================================*/

int cim_read(unsigned char *buf)
{
  return cim_start_dma(buf);
}

void cim_close(void)
{
        cim_stop();  //
  	free_irq(IRQ_CIM);
	cim_fb_destroy();
}


/*==========================================================================
 * Interrupt handler
 *========================================================================*/

static void cim_irq_handler(unsigned int arg)
{
	u32 state = REG_CIM_STATE;
#if 0
	if (state & CIM_STATE_DMA_EOF) {
	  //		wake_up_interruptible(&cim_dev->wait_queue);
	  OSSemPost(cim_dev->WaitSem);
	}
#endif
	if (state & CIM_STATE_DMA_STOP) {
		// Got a frame, wake up wait routine
	  //		wake_up_interruptible(&cim_dev->wait_queue);
	  // printf("irq \n");
	  OSSemPost(cim_dev->WaitSem);
	}

	// clear status flags
	REG_CIM_STATE = 0;
}

/*==========================================================================
 * Module init and exit
 *========================================================================*/

int cim_init(void)
{
        static struct cim_device *dev;
	int ret;
	cim_config_t c;
	static struct cim_device dev0;

	/* config cim */
	c.mclk = cim_cfg.mclk;
	c.cfg = (cim_cfg.vsp << 14) | (cim_cfg.hsp << 13) | (cim_cfg.pcp << 12) | (cim_cfg.dsm << 0) | (cim_cfg.pack << 4) | (cim_cfg.inv_dat << 15);
	c.ctrl = (cim_cfg.frc << 16) | (cim_cfg.trig << 4);
	cim_config(&c);

	/* cim image parameter isn't set newly */

	/* allocate device */
        dev = &dev0;
	/* record device */
	cim_dev = dev;

	/* allocate a frame buffer */
	if (cim_fb_alloc() < 0) {
		return -1;
	}

	//	init_waitqueue_head(&dev->wait_queue);
	dev->WaitSem = OSSemCreate(0);

	if ((ret = request_irq(IRQ_CIM, cim_irq_handler, dev)) == -1) {
		cim_fb_destroy();
		printf("CIM could not get IRQ");
		return ret;
	}

	//	printf("JzSOC Camera Interface Module (CIM) driver OK\n");

	return 0;
}