This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DM368EVM EMIF Write and Read Glitches

Hi there,

I have a DM368EVM Rev G and we have added our own FPGA to the J14 EMIF expansion header.  The FPGA is sharing the bus with the CPLD U33 onboard the DM368EVM.  I have mapped the FPGA into some of the unused portions of memory within the CPLD's address range.  Here is the memory mapping that's currently setup:

/*   
                        CPLD Registers on the DM368 EVM
  
        Reg #     Entire Address  A13-A8           A2-A1     Function                                                           
        0              0x0400 0000     0 0 0 0 0 0     0 0          CPLD Version                                                
        1              0x0400 0008     0 0 0 0 0 0     0 1          Test Register                                                  
        2              0x0400 0010     0 0 0 0 0 0     1 0          LED Register                                                  
        3              0x0400 0018     0 0 0 0 0 0     1 1          Board Mux Control                                        
        4              0x0400 0400     0 0 0 0 0 1     0 0          Board Switch Register                                  
        5              0x0400 0408     0 0 0 0 0 1     0 1          Power Control Register                               
        6              0x0400 0410     0 0 0 0 0 1     1 0          GPIO Video Register                                    
        7              0x0400 0418     0 0 0 0 0 1     1 1          Media Card Status                                        
        8              0x0400 0800     0 0 0 0 1 0     0 0          DILC Output Pin Mapping                            
        9              0x0400 0808     0 0 0 0 1 0     0 1          DILC Input Pin Mapping                                
        10            0x0400 0810     0 0 0 0 1 0    1 0           Imager Internal I/O Direction Register 0     
        11            0x0400 0818     0 0 0 0 1 0    1 1           Imager Internal I/O Mux Register 0              
        12            0x0400 0C00     0 0 0 0 1 1    0 0          Imager Internal I/O Mux Register 1              
        13            0x0400 0C08     0 0 0 0 1 1    0 1          Imager Internal I/O Direction Register 1     
        14            0x0400 0C10     0 0 0 0 1 1    1 0          Imager Internal I/O Mux Register 2              
        15            0x0400 0C18     0 0 0 0 1 1    1 1          Imager Internal I/O Mux Register 3              
        16            0x0400 1000     0 0 0 1 0 0     0 0          Imager Internal I/O Direction Register 2      
        17            0x0400 1008     0 0 0 1 0 0     0 1          Imager Internal I/O Mux Register 4               
        18            0x0400 1010     0 0 0 1 0 0     1 0          Imager Internal I/O Mux Register 5               
        19            0x0400 1018     0 0 0 1 0 0     1 1          Board RESET Register                                   
        20            0x0400 1400    0 0 0 1 0 1      0 0          Interrupt Register                                             
       
        24            0x0400 1800    0 0 0 1 1 0      0 0          CPLD Test Register 0                                     
        25            0x0400 1808    0 0 0 1 1 0      0 1          CPLD Test Register 1                                     
        26            0x0400 1810    0 0 0 1 1 0      1 0          CPLD Test Register 2                                     
        27            0x0400 1818    0 0 0 1 1 0      1 1          CPLD Test Register 3                                     
        28            0x0400 1C00    0 0 0 1 1 1      0 0         CPLD Test Register 4                                     
        29            0x0400 1C08    0 0 0 1 1 1      0 1         CPLD Test Register 5                                     
        30            0x0400 1C10    0 0 0 1 1 1      1 0         CPLD Test Register 6                                     
        31            0x0400 1C18    0 0 0 1 1 1      1 1         CPLD Test Register 7                                    

        32            0x0400 2000    0 0 1 0 0 0       0 0         FPGA Register 0                                              
        33            0x0400 2008    0 0 1 0 0 0       0 1         FPGA Register 1                                              
        34            0x0400 2010    0 0 1 0 0 0       1 0         FPGA Register 2                                              
        35            0x0400 2018    0 0 1 0 0 0       1 1         FPGA Register 3                                              
        36            0x0400 2400    0 0 1 0 0 1       0 0         FPGA Register 4                                              
        37            0x0400 2408    0 0 1 0 0 1       0 1         FPGA Register 5                                              
        38            0x0400 2410    0 0 1 0 0 1       1 0         FPGA Register 6                                              
        39            0x0400 2418    0 0 1 0 0 1       1 1         FPGA Register 7                                             

        720          0x0400 F800     1 1 1 1 1 0      0 0         CCD Internal I/O Direction Register 1         
        721          0x0400 F808     1 1 1 1 1 0      0 1         CCD Internal I/O Read/Write Register 1     
        722          0x0400 F810     1 1 1 1 1 0      1 0         CCD Internal I/O Direction Register 2         
        723          0x0400 F818     1 1 1 1 1 0      1 1         CCD Internal I/O Read/Write Register 2     
        724          0x0400 FC00     1 1 1 1 1 1     0 0         CCD Internal I/O Direction Register 3         
        725          0x0400 FC08     1 1 1 1 1 1     0 1         CCD Internal I/O Read/Write Register 3     
       
    */

FPGA registers begin at address 0x04002000.  I have modified the CPLD firmware to tri-state the data bus when not accessing one of its registers.  It previously output the contents of register 0, version register, when the address went beyond it's decoded register set.  I also added 8 test registers from registers 24 to 31.

I've been testing the interface to the FPGA, as we have a custom cable running between J14 on the EVM and the FPGA to interface the appropriate EMIF signals.  These are:

        DM368EVM_EMIF_D : inout  STD_LOGIC_VECTOR (7 downto 0);
        DM368EVM_EMIF_WE : in  STD_LOGIC;
        DM368EVM_EMIF_CE1 : in  STD_LOGIC;
        DM368EVM_EMIF_OE : in  STD_LOGIC;
        DM368EVM_EMIF_SEL : in  STD_LOGIC;
        DM368EVM_EMIF_A1 : in  STD_LOGIC;
        DM368EVM_EMIF_A2 : in  STD_LOGIC;
        DM368EVM_EMIF_A9 : in  STD_LOGIC;
        DM368EVM_EMIF_A8 : in  STD_LOGIC;
        DM368EVM_EMIF_A11 : in  STD_LOGIC;
        DM368EVM_EMIF_A10 : in  STD_LOGIC;
        DM368EVM_EMIF_A13 : in  STD_LOGIC;
        DM368EVM_EMIF_A12 : in  STD_LOGIC;

For the most part, the interface appears to be working well.  I can read and write registers within the CPLD and the FPGA without interfering with each other.  My test software generates a random fpga register value and random 8bit value, writes the value and reads it back, testing to see if what was written and what was readback are matching, to ensure valid data is being transferred.  I loop this for about 100,000,000 iterations, which runs for about 2min.  If the values don't match, I trigger an error flag and I'm able to capture the status of various signals on our logic analyzer.

Every once in awhile, I get ringing on the WE, CE1 and OE lines, which causes data corruption.  It doesn't appear to be electrical noise, as I can cause the error to occur repeatedly by commenting out the random number seed in the software.  This makes the random number generation repeatable through multiple runs of the software.


Attached is a plot showing what's happening:

 

You can see that at around the -3us mark, a valid write and read cycle occured.  However, on the following write and read cycle, just after the -1us mark, the write cycle appears valid, but on the read to validate what was written, the CE, WE and OE lines begin to ring and I get a corrupted readback. 

I've managed to suppress the write glitching by adding a glitch filter to the FPGA firmware.  I can't seem to figure out what to do prevent the remainder of the glitching from occuring.  The value it was attempting to write was 0xFF to fpga register number 4. 

Has anyone else seen such behavior from the EMIF port?  Any ideas what may be causing this type of glitch?

Thanks

Derek

 

  • Hi,

    I believe I managed to fix the issue:

    The glitches that occured seemed to be coming from the NAND, the NAND being tied to CE0 chip enable space.  Even though I was doing reads and writes to CE1 memory space, every once in awhile, it seems that the NAND assumes an access to it and corrupts the data bus. 

    I checked the level of CE0 on the logic analyzer and it seems to be always low (ground), enabling the NAND permenantly.  I'm not sure if it's supposed to be that way. 

    I modified the CPLD firmware slightly to tri-state the data bus and disable the NAND chip select when the test register (register 1) in the CPLD is anything but the default value of 0xA5.  By doing so, I can ensure no interference between either the CPLD or the NAND when attempting to access the FPGA.  Writing the test register back to 0xA5 re-enables both the CPLD and NAND.  Here are the modified lines of code

      pEM_EMU_DATA <= cpld_reg_data when cpld_regen = '1' and cpld_regrd = '0' and cpld_reg1 = "10100101" else "ZZZZZZZZ"; 

    as well as

      pNAND_CE0n   <= pEM_CE0 when pSEL_NAND_LOW = '0' and pEM_A12 = '0' and cpld_reg1 = "10100101" else '1';
      pNAND_CE1n   <= pEM_CE0 when pSEL_NAND_LOW = '0' and pEM_A12 = '1' and cpld_reg1 = "10100101" else '1';
      pONENAND_CEn <= pEM_CE0 when pSEL_NAND_LOW = '1' and cpld_reg1 = "10100101" else '1';

    Cheers

    Derek

  • Hi,

    One final comment, I made a simpler fix to the above solution which is to disable the nand and onenand chip selects whenever ce1 is selected.  Also changed from register 1 to register 21 to allow indepent disabling of the cpld readbus and the nand/onenand chip selects.  Attached the project file.  A few comments about the updated firmware:

    - The data bus is tristated when it's registers are not being accessed.  The code previously output the contents of registers 0.  Since I've mapped our fpga into the unused register locations within CE1 space, I needed this operation to be tri-state.

    - A bank of test registers were added, 8 in total.  These are registers 24 through 31 in the firmware. 

    - The read bus from the CPLD can be temporarily tri-stated by writing register 1 to something other than default of hex value A5.  Re-enable by writing back to A5

    - The chip selects to the NAND and ONENAND can be temporarily tri-stated by writing register 21 to something other than the default of hex A5.  Re-enable by writing back to A5. 

    Best Regards,

    Derek

    Updated DM368EVM REVG firmware: 8625.EVMDM368_CPLD_LATEST.zip

  • Hi Richardson,

    I am using dm368 emif to communicate fpga with CE1. I see the address of ASYNC EMIF Data (CE1) is from 0x04000000 to 0x05FFFFFF, when i read the address of 0x04000000, the error says that "Unable to handle kernel paging request at virtual address 01000000", and I can see the CE1 signal is not low when i read the address.

    I have connect the D0-D15, A0-A13,BA0, BA1 from dm368 to FPGA.

    what is wrong am i? can you help me?

  • Hi Jammy Dane, how are you?  I haven't worked on this project for years now but it sounds like your software is incorrectly accessing the memory location.

    Are you using the DM368EVM with an FPGA like I was or do you have your own board with a DM368 and FPGA?

    What does your c code look like for accessing the emif port?

    I have attached some sample code which I found on my old development PC which I believe I used for testing the interface.  Hope it helps

    Best Regards

    Derek

    /*
     * Module: main.c
     *
     * Description: This program is used to test write and readback of the CPLD
     * 		registers.
     *
     * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
     *
     *
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *    Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     *    Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the
     *    distribution.
     *
     *    Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
    */
    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <errno.h>
    #include <signal.h>
    #include <fcntl.h>
    #include <ctype.h>
    #include <termios.h>
    #include <time.h>
    #include <sys/types.h>
    #include <sys/mman.h>
    #include <sys/time.h>
    #include <sys/io.h>
    
    
    #define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
      __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)
    
    /*
     * A MAX-II CPLD is used for various board control functions. U33 on the DM368 EVM
     */
    
    #define CPLD_MAP_SIZE 16384UL			/* MAP_SIZE of 8192 gives us 32 registers worth of memory access */
    #define CPLD_MAP_MASK (CPLD_MAP_SIZE - 1)
    #define CPLD_BASE 0x04000000 			/*  CPLD Base Address, Beginning at Chip Select 1 base */
    
    #define CPLD_REG(cpldregoff)	((cpldregoff & 0XFC) << 8) + ((cpldregoff & 0x3) << 3)
    
    #define CPLD_VERSION		CPLD_REG(0)	/* r/o */
    #define CPLD_TEST		CPLD_REG(1)
    #define CPLD_LEDS		CPLD_REG(2)
    #define CPLD_MUX		CPLD_REG(3)
    #define CPLD_SWITCH		CPLD_REG(4)	/* r/o */
    #define CPLD_POWER		CPLD_REG(5)
    #define CPLD_VIDEO		CPLD_REG(6)
    #define CPLD_CARDSTAT		CPLD_REG(7)	/* r/o */
    
    #define CPLD_DILC_OUT		CPLD_REG(8)
    #define CPLD_DILC_IN		CPLD_REG(9)	/* r/o */
    
    #define CPLD_IMG_DIR0		CPLD_REG(10)
    #define CPLD_IMG_MUX0		CPLD_REG(11)
    #define CPLD_IMG_MUX1		CPLD_REG(12)
    #define CPLD_IMG_DIR1		CPLD_REG(13)
    #define CPLD_IMG_MUX2		CPLD_REG(14)
    #define CPLD_IMG_MUX3		CPLD_REG(15)
    #define CPLD_IMG_DIR2		CPLD_REG(16)
    #define CPLD_IMG_MUX4		CPLD_REG(17)
    #define CPLD_IMG_MUX5		CPLD_REG(18)
    
    #define CPLD_RESETS		CPLD_REG(19)
    
    #define CPLD_TS_CFG		CPLD_REG(20)
    
    #define CPLD_TEST_REG24 	CPLD_REG(24)
    #define CPLD_TEST_REG25 	CPLD_REG(25)
    #define CPLD_TEST_REG26 	CPLD_REG(26)
    #define CPLD_TEST_REG27 	CPLD_REG(27)
    #define CPLD_TEST_REG28 	CPLD_REG(28)
    #define CPLD_TEST_REG29 	CPLD_REG(29)
    #define CPLD_TEST_REG30 	CPLD_REG(30)
    #define CPLD_TEST_REG31 	CPLD_REG(31)
    
    /*
     * FPGA on the Polaris Amplifier, mapped into CE1 chip select memory space at address 0x04002000
     */
    
    #define FPGA_BASE 0x04002000 		/*  CPLD Base Address, Beginning at Chip Select 1 base */
    
    #define FPGA_REG(fpgaregoff)	((fpgaregoff & 0XFC) << 8) + ((fpgaregoff & 0x3) << 3)
    
    #define FPGA_REGISTER0	FPGA_REG(0)
    #define FPGA_REGISTER1	FPGA_REG(1)
    #define FPGA_REGISTER2	FPGA_REG(2)
    #define FPGA_REGISTER3	FPGA_REG(3)
    #define FPGA_REGISTER4	FPGA_REG(4)
    #define FPGA_REGISTER5	FPGA_REG(5)
    #define FPGA_REGISTER6	FPGA_REG(6)
    #define FPGA_REGISTER7	FPGA_REG(7)
    #define FPGA_REGISTER8	FPGA_REG(8)
    
    #define ASYNC_EMIF_CONTROL_BASE 0x01D10000
    #define ASYNC_EMIF_MAP_SIZE 4192UL
    #define ASYNC_EMIF_MAP_MASK (ASYNC_EMIF_MAP_SIZE - 1)
    
    #define R_HOLD 0
    #define R_STROBE 10
    #define R_SETUP 0
    
    #define W_HOLD 0
    #define W_STROBE 10
    #define W_SETUP 0
    
    
    int main(int argc, char **argv)
    {
    	int fd;
    	unsigned long writeval;
    	unsigned long numLoops;
    	off_t regnum;
    	off_t regnum_to_address;
     	struct timeval        tv;
    	unsigned long         T0s;
        	unsigned long         T1s;
    	void *virt_addr;
    	void *cpld_virtual_map_base;
    	void *async_emif_virtual_map_base;
    	unsigned char fpga_writeval;
    	unsigned char fpga_readval;
    	unsigned char err_reg;
    	int r;
    	int percent_complete;
    
    	unsigned long emif_reg;
    
    	/*
    						CPLD Registers on the DM368 EVM
    
    		Reg # 	Entire Address 	Address A13-A8 	Address A2-A1 	Function 					R/W
    		0 	0x0400 0000 	0 0 0 0 0 0 	0 0 		CPLD Version 					R
    		1 	0x0400 0008 	0 0 0 0 0 0 	0 1 		Test Register 					R,W
    		2 	0x0400 0010 	0 0 0 0 0 0 	1 0 		LED Register 					R,W
    		3 	0x0400 0018 	0 0 0 0 0 0 	1 1 		Board Mux Control 				R,W
    		4 	0x0400 0400 	0 0 0 0 0 1 	0 0 		Board Switch Register 				R
    		5 	0x0400 0408 	0 0 0 0 0 1 	0 1 		Power Control Register 				R,W
    		6 	0x0400 0410 	0 0 0 0 0 1 	1 0 		GPIO Video Register 				R,W
    		7 	0x0400 0418 	0 0 0 0 0 1 	1 1 		Media Card Status 				R
    		8 	0x0400 0800 	0 0 0 0 1 0 	0 0 		DILC Output Pin Mapping 			R,W
    		9 	0x0400 0808 	0 0 0 0 1 0 	0 1 		DILC Input Pin Mapping 				R
    		10 	0x0400 0810 	0 0 0 0 1 0 	1 0 		Imager Internal I/O Direction Register 0 	R,W
    		11 	0x0400 0818 	0 0 0 0 1 0 	1 1 		Imager Internal I/O Mux Register 0 		R,W
    		12 	0x0400 0C00 	0 0 0 0 1 1 	0 0 		Imager Internal I/O Mux Register 1 		R,W
    		13 	0x0400 0C08 	0 0 0 0 1 1 	0 1 		Imager Internal I/O Direction Register 1 	R,W
    		14 	0x0400 0C10 	0 0 0 0 1 1 	1 0 		Imager Internal I/O Mux Register 2 		R,W
    		15 	0x0400 0C18 	0 0 0 0 1 1 	1 1 		Imager Internal I/O Mux Register 3 		R,W
    		16 	0x0400 1000 	0 0 0 1 0 0 	0 0 		Imager Internal I/O Direction Register 2 	R,W
    		17 	0x0400 1008 	0 0 0 1 0 0 	0 1 		Imager Internal I/O Mux Register 4 		R,W
    		18 	0x0400 1010 	0 0 0 1 0 0 	1 0	 	Imager Internal I/O Mux Register 5 		R,W
    		19 	0x0400 1018 	0 0 0 1 0 0 	1 1 		Board RESET Register 				R,W
    		20	0x0400 1400	0 0 0 1 0 1	0 0 		Interrupt Register				R,W
    
    		24	0x0400 1800	0 0 0 1 1 0	0 0 		CPLD Test Register 0				R,W
    		25	0x0400 1808	0 0 0 1 1 0	0 1 		CPLD Test Register 1	 			R,W
    		26	0x0400 1810	0 0 0 1 1 0	1 0 		CPLD Test Register 2				R,W
    		27	0x0400 1818	0 0 0 1 1 0	1 1 		CPLD Test Register 3				R,W
    		28	0x0400 1C00	0 0 0 1 1 1	0 0 		CPLD Test Register 4				R,W
    		29	0x0400 1C08	0 0 0 1 1 1	0 1 		CPLD Test Register 5				R,W
    		30	0x0400 1C10	0 0 0 1 1 1	1 0 		CPLD Test Register 6				R,W
    		31	0x0400 1C18	0 0 0 1 1 1	1 1 		CPLD Test Register 7				R,W
    
    		32      0x0400 2000	0 0 1 0 0 0	0 0 		FPGA Register 0					R,W
    		33      0x0400 2008	0 0 1 0 0 0	0 1 		FPGA Register 1					R,W
    		34      0x0400 2010	0 0 1 0 0 0	1 0 		FPGA Register 2					R,W
    		35      0x0400 2018	0 0 1 0 0 0	1 1 		FPGA Register 3					R,W
    		36      0x0400 2400	0 0 1 0 0 1	0 0 		FPGA Register 4					R,W
    		37      0x0400 2408	0 0 1 0 0 1	0 1 		FPGA Register 5					R,W
    		38      0x0400 2410	0 0 1 0 0 1	1 0 		FPGA Register 6					R,W
    		39      0x0400 2418	0 0 1 0 0 1	1 1 		FPGA Register 7					R,W
    
    		720 	0x0400 F800 	1 1 1 1 1 0 	0 0 		CCD Internal I/O Direction Register 1 		R,W
    		721 	0x0400 F808 	1 1 1 1 1 0 	0 1 		CCD Internal I/O Read/Write Register 1 		R,W
    		722 	0x0400 F810 	1 1 1 1 1 0 	1 0 		CCD Internal I/O Direction Register 2 		R,W
    		723 	0x0400 F818 	1 1 1 1 1 0 	1 1 		CCD Internal I/O Read/Write Register 2 		R,W
    		724 	0x0400 FC00 	1 1 1 1 1 1 	0 0 		CCD Internal I/O Direction Register 3 		R,W
    		725 	0x0400 FC08 	1 1 1 1 1 1 	0 1 		CCD Internal I/O Read/Write Register 3 		R,W
    
    	*/
    
    	/* /dev/mem provides access to the system physical memory.  */
    	if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
    
    	/* Map one page for CPLD access */
    	cpld_virtual_map_base = mmap(0, CPLD_MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, CPLD_BASE & ~CPLD_MAP_MASK);
    	if(cpld_virtual_map_base == (void *) -1) FATAL;
    
    	async_emif_virtual_map_base = mmap(0, ASYNC_EMIF_MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, ASYNC_EMIF_CONTROL_BASE & ~ASYNC_EMIF_MAP_MASK);
    	if(async_emif_virtual_map_base == (void *) -1) FATAL;
    
    	printf("\n EMIF REGISTERS \n");
    
    	virt_addr = async_emif_virtual_map_base + (ASYNC_EMIF_CONTROL_BASE+0x4 & ASYNC_EMIF_MAP_MASK);
    	emif_reg = *((unsigned long *) virt_addr);
    	printf("Virtual Address = %p Actual Address = %p  Value = %p\n",virt_addr,ASYNC_EMIF_CONTROL_BASE+0x4,emif_reg);
    
    	virt_addr = async_emif_virtual_map_base + (ASYNC_EMIF_CONTROL_BASE+0x10 & ASYNC_EMIF_MAP_MASK);
    	emif_reg = *((unsigned long *) virt_addr);
    	printf("Virtual Address = %p Actual Address = %p  Value = %p\n",virt_addr,ASYNC_EMIF_CONTROL_BASE+0x10,emif_reg);
    
    	virt_addr = async_emif_virtual_map_base + (ASYNC_EMIF_CONTROL_BASE+0x14 & ASYNC_EMIF_MAP_MASK);
    	emif_reg = *((unsigned long *) virt_addr);
    	printf("Virtual Address = %p Actual Address = %p  Value = %p\n",virt_addr,ASYNC_EMIF_CONTROL_BASE+0x14,emif_reg);
    	// Clear W_SETUP, W_STROBE and W_HOLD and R_SETUP, R_STROBE and R_HOLD
    	emif_reg &= 0xC000000F;
    	// Set W_SETUP, W_STROBE and W_HOLD and R_SETUP, R_STROBE and R_HOLD
    	emif_reg = (emif_reg | (R_HOLD << 4));
    	emif_reg = (emif_reg | (R_STROBE << 7));
    	emif_reg = (emif_reg | (R_SETUP << 13));
    	emif_reg = (emif_reg | (W_HOLD << 13));
    	emif_reg = (emif_reg | (W_STROBE << 20));
    	emif_reg = (emif_reg | (W_SETUP << 26));
    	*((unsigned long *) virt_addr) = emif_reg;
    	emif_reg = *((unsigned long *) virt_addr);
    	printf("Virtual Address = %p Actual Address = %p  Value = %p\n",virt_addr,ASYNC_EMIF_CONTROL_BASE+0x14,emif_reg);
    
    	/* Cycle through LEDS on the eval board, connected to register 2 in the CPLD */
    	printf("\n Blinking Leds... \n");
    /*	regnum = 2;
    	regnum_to_address = (((regnum & 0XFC) << 8) + ((regnum & 0X3) << 3));
    	virt_addr = cpld_virtual_map_base + (CPLD_BASE+CPLD_LEDS & CPLD_MAP_MASK);
    	for(writeval=0;writeval<256;writeval++)
    	{
    		*((unsigned char *) virt_addr) = writeval;
    		usleep( 33333 );
    	}  */
    	printf(" Blinking Leds Complete...\n");
    
    	printf("\n Testing readback of first 21 registers \n\n");
    
    	/* Readback first 20 registers in the CPLD */
    	for(regnum = 0; regnum <= 20; regnum++)
    	{
    		regnum_to_address = (((regnum & 0XFC) << 8) + ((regnum & 0X3) << 3));
    		virt_addr = cpld_virtual_map_base + (CPLD_BASE+regnum_to_address & CPLD_MAP_MASK);
    		printf("Virtual Address = %p Actual Address = %p ",virt_addr,CPLD_BASE+regnum_to_address);
    		printf("Register %d = %p\n",regnum,*((unsigned char *) virt_addr));
    	}
    
    	printf("\n Testing out of range address \n\n");
    
    	/* Test out of range CPLD address, should be tri-stated */
    	for(regnum = 21; regnum <= 23; regnum++)
    	{
    		regnum_to_address = (((regnum & 0XFC) << 8) + ((regnum & 0X3) << 3));
    		virt_addr = cpld_virtual_map_base + (CPLD_BASE+regnum_to_address & CPLD_MAP_MASK);
    		printf("Virtual Address = %p Actual Address = %p ",virt_addr,CPLD_BASE+regnum_to_address);
    		printf("Register %d = %p\n",regnum,*((unsigned char *) virt_addr));
    	}
    
    //	virt_addr = cpld_virtual_map_base + (CPLD_BASE+CPLD_TEST & CPLD_MAP_MASK);
    //	*((unsigned char *) virt_addr) = 0;
    
    	/* Readback first 20 registers in the CPLD */
    	for(regnum = 0; regnum <= 20; regnum++)
    	{
    		regnum_to_address = (((regnum & 0XFC) << 8) + ((regnum & 0X3) << 3));
    		virt_addr = cpld_virtual_map_base + (CPLD_BASE+regnum_to_address & CPLD_MAP_MASK);
    		printf("Virtual Address = %p Actual Address = %p ",virt_addr,CPLD_BASE+regnum_to_address);
    		printf("Register %d = %p\n",regnum,*((unsigned char *) virt_addr));
    	}
    
    	printf("\n Testing scratch registers \n\n");
    
    	/* Test scratch register 24 */
    
    
    /*	if (gettimeofday(&tv, NULL) == -1) {
    		printf("Failed to get os time\n");
    	}
    
    	T0s = tv.tv_sec * 1000000 + tv.tv_usec;
    
    	regnum = 24;
    	regnum_to_address = (((regnum & 0XFC) << 8) + ((regnum & 0X3) << 3));
    	virt_addr = cpld_virtual_map_base + (CPLD_BASE+regnum_to_address & CPLD_MAP_MASK);
    	printf("Virtual Address = %p Actual Address = %p ",virt_addr,CPLD_BASE+regnum_to_address);
    
    	for(numLoops = 0; numLoops < 42000; numLoops++)
    	{
    		*((unsigned char *) virt_addr) = (unsigned char)(numLoops & 0xFF);
    	}
    
    	if (gettimeofday(&tv, NULL) == -1) {
    		printf("Failed to get os time\n");
    	}
    
    	T1s = tv.tv_sec * 1000000 + tv.tv_usec;
    
    	printf("T0: %d T1: %d Delta: %duSec\n",T0s,T1s,T1s-T0s); */
    
    	/* Test CPLD Register Access */
    
    	printf("\n Testing CPLD Registers \n\n");
    	percent_complete = 0;
    
    	virt_addr = cpld_virtual_map_base + (FPGA_BASE+FPGA_REGISTER8 & CPLD_MAP_MASK);
    
    	writeval = 0;
    	fpga_writeval = (unsigned char)writeval;
    	*((unsigned char *) virt_addr) = fpga_writeval;
    	fpga_readval = *((unsigned char *) virt_addr);
    
    //	srand((unsigned)(time(0)));
    	for(numLoops = 0; numLoops < 100000000; numLoops++)
    	{
    		// Generate random register location between 0 and 7
    		regnum = (int)((8.0*rand())/((double)RAND_MAX+1.0))+24;
    		regnum_to_address = (((regnum & 0XFC) << 8) + ((regnum & 0X3) << 3));
    		virt_addr = cpld_virtual_map_base + (CPLD_BASE+regnum_to_address & CPLD_MAP_MASK);
    
    		writeval = (int)((256.0*rand())/((double)RAND_MAX+1.0));
    		fpga_writeval = (unsigned char)writeval;
    
    		*((unsigned char *) virt_addr) = fpga_writeval;
    		fpga_readval = *((unsigned char *) virt_addr);
    		if(fpga_writeval != fpga_readval)
    		{
    			/* Set the error flag */
    			virt_addr = cpld_virtual_map_base + (FPGA_BASE+FPGA_REGISTER8 & CPLD_MAP_MASK);
    			*((unsigned char *) virt_addr) = 1;
    			err_reg = *((unsigned char *) virt_addr);
    
    			printf("Error: Mismatched write and read values Loop Number %d REG: %d WR: %p RD: %p\n",numLoops,regnum,fpga_writeval,fpga_readval);
    			/* 3x re-read of the register which failed */
    			regnum_to_address = (((regnum & 0XFC) << 8) + ((regnum & 0X3) << 3));
    			virt_addr = cpld_virtual_map_base + (CPLD_BASE+regnum_to_address & CPLD_MAP_MASK);
    
    			printf("  REREAD1 Virtual Address = %p Actual Address = %p  FPGA Register %d = %p\n",virt_addr,CPLD_BASE+regnum_to_address,regnum,*((unsigned char *) virt_addr));
    
    			printf("  REREAD2 Virtual Address = %p Actual Address = %p  FPGA Register %d = %p\n",virt_addr,CPLD_BASE+regnum_to_address,regnum,*((unsigned char *) virt_addr));
    
    			printf("  REREAD3 Virtual Address = %p Actual Address = %p  FPGA Register %d = %p\n",virt_addr,CPLD_BASE+regnum_to_address,regnum,*((unsigned char *) virt_addr));
    			printf("Register Dump: \n");
    			for(regnum = 24;regnum<32;regnum++)
    			{
    				regnum_to_address = (((regnum & 0XFC) << 8) + ((regnum & 0X3) << 3));
    				virt_addr = cpld_virtual_map_base + (CPLD_BASE+regnum_to_address & CPLD_MAP_MASK);
    				printf("  Virtual Address = %p Actual Address = %p ",virt_addr,CPLD_BASE+regnum_to_address);
    				printf("  CPLD Register %d = %p\n",regnum,*((unsigned char *) virt_addr));
    			}
    
    			/* Clear the error register */
    			virt_addr = cpld_virtual_map_base + (FPGA_BASE+FPGA_REGISTER8 & CPLD_MAP_MASK);
    			*((unsigned char *) virt_addr) = 0;
    			break;
    		}
    		if((numLoops % 5000000) == 0)
    		{
    			printf(" %d%% complete\r",percent_complete);
    			fflush(stdout);
    			percent_complete+=5;
    		}
    	}
    
    	printf("\n\n Testing CPLD Registers Complete\n\n");
    
    	/* Test FPGA Register Access */
    
    	printf("\n Testing FPGA Registers \n\n");
    	percent_complete = 0;
    
    	/* Clear error flag */
    	virt_addr = cpld_virtual_map_base + (FPGA_BASE+FPGA_REGISTER8 & CPLD_MAP_MASK);
    
    	writeval = 0;
    	fpga_writeval = (unsigned char)writeval;
    	*((unsigned char *) virt_addr) = fpga_writeval;
    	fpga_readval = *((unsigned char *) virt_addr);
    
    
    	/* Start the test */
    	for(numLoops = 0; numLoops < 100000000; numLoops++)
    	{
    		/* Generate random register location between 0 and 7 */
    		regnum = (int)((8.0*rand())/((double)RAND_MAX+1.0));
    		regnum_to_address = (((regnum & 0XFC) << 8) + ((regnum & 0X3) << 3));
    		virt_addr = cpld_virtual_map_base + (FPGA_BASE+regnum_to_address & CPLD_MAP_MASK);
    
    		/* Generate random write value between 0 and 255 */
    		writeval = (int)((256.0*rand())/((double)RAND_MAX+1.0));
    		fpga_writeval = (unsigned char)writeval;
    
    		/* Write it out */
    		*((unsigned char *) virt_addr) = fpga_writeval;
    		/* Read it back */
    		fpga_readval = *((unsigned char *) virt_addr);
    
    		/* Check for matching write and read values */
    		if(fpga_writeval != fpga_readval)
    		{
    			/* Set the error flag */
    			virt_addr = cpld_virtual_map_base + (FPGA_BASE+FPGA_REGISTER8 & CPLD_MAP_MASK);
    			*((unsigned char *) virt_addr) = 1;
    			err_reg = *((unsigned char *) virt_addr);
    
    			printf("Error: Mismatched write and read values Loop Number %d REG: %d WR: %p RD: %p\n",numLoops,regnum,fpga_writeval,fpga_readval);
    
    
    			/* 3x re-read of the register which failed */
    			regnum_to_address = (((regnum & 0XFC) << 8) + ((regnum & 0X3) << 3));
    			virt_addr = cpld_virtual_map_base + (FPGA_BASE+regnum_to_address & CPLD_MAP_MASK);
    
    			printf("  REREAD1 Virtual Address = %p Actual Address = %p  FPGA Register %d = %p\n",virt_addr,FPGA_BASE+regnum_to_address,regnum,*((unsigned char *) virt_addr));
    
    			printf("  REREAD2 Virtual Address = %p Actual Address = %p  FPGA Register %d = %p\n",virt_addr,FPGA_BASE+regnum_to_address,regnum,*((unsigned char *) virt_addr));
    
    			printf("  REREAD3 Virtual Address = %p Actual Address = %p  FPGA Register %d = %p\n",virt_addr,FPGA_BASE+regnum_to_address,regnum,*((unsigned char *) virt_addr));
    			printf("Register Dump: \n");
    			/* Dump the registers to screen */
    			for(regnum = 0;regnum<8;regnum++)
    			{
    				regnum_to_address = (((regnum & 0XFC) << 8) + ((regnum & 0X3) << 3));
    				virt_addr = cpld_virtual_map_base + (FPGA_BASE+regnum_to_address & CPLD_MAP_MASK);
    				printf("  Virtual Address = %p Actual Address = %p  FPGA Register %d = %p\n",virt_addr,FPGA_BASE+regnum_to_address,regnum,*((unsigned char *) virt_addr));
    			}
    			printf("Register Dump Again: \n");
    			for(regnum = 0;regnum<8;regnum++)
    			{
    				regnum_to_address = (((regnum & 0XFC) << 8) + ((regnum & 0X3) << 3));
    				virt_addr = cpld_virtual_map_base + (FPGA_BASE+regnum_to_address & CPLD_MAP_MASK);
    				printf("  Virtual Address = %p Actual Address = %p  FPGA Register %d = %p\n",virt_addr,FPGA_BASE+regnum_to_address,regnum,*((unsigned char *) virt_addr));
    			}
    
    			/* Clear the error register */
    			virt_addr = cpld_virtual_map_base + (FPGA_BASE+FPGA_REGISTER8 & CPLD_MAP_MASK);
    			*((unsigned char *) virt_addr) = 0;
    			break;
    		}
    		/* Print percentage complete every 5% through the loop */
    		if((numLoops % 5000000) == 0)
    		{
    			printf(" %d%% complete\r",percent_complete);
    			fflush(stdout);
    			percent_complete+=5;
    		}
    	}
    
    	printf("\n\n Testing FPGA Registers Complete\n\n");
    
    	virt_addr = cpld_virtual_map_base + (CPLD_BASE+CPLD_TEST & CPLD_MAP_MASK);
    	*((unsigned char *) virt_addr) = 0xA5;
    
    	if(munmap(cpld_virtual_map_base, CPLD_MAP_SIZE) == -1) FATAL;
    	if(munmap(async_emif_virtual_map_base, ASYNC_EMIF_MAP_SIZE) == -1) FATAL;
    	close(fd);
    
    	printf("\n Test Complete\n\n");
    	return 0;
    }
    

  • ///////////////////////////
    // changed by Wugang at 2009.02.19
    //////////////////////////
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/delay.h>              // udelay()
    #include <linux/fs.h>                     // everything...
    #include <asm/uaccess.h>          // copy_from/to_user
    #include <linux/cdev.h>
    //#include <linux/devfs_fs_kernel.h>	/* for devfs */
    // Definition for fpga Base Address and the local Power or Sleep Controller LPSoC
    #include <mach/hardware.h> 
    #include <mach/clock.h>
    #include <linux/platform_device.h>
    #include <linux/clk.h>
    #include <linux/spinlock.h>
    #include <linux/proc_fs.h>
    #include <linux/sysctl.h>
    #include <linux/interrupt.h>
    #include <linux/device.h>
    #include <linux/irq.h>
    #include <asm/io.h>
    //#include <asm/arch/gio.h>
    ///////////////////////////
    // DEFINITIONS & GLOBALS
    //////////////////////////
    // Register definitions to control the fpga,refer to dm355 fpga referrence guide.pdf
    #define AEMIFBASE			0x04000000
    
    #define FPGA_BUF			4096
    
    // Macro for accessing a memory location such as a register
    #define fpga_REG(reg)    (*(int *__iomem) IO_ADDRESS(reg))
    
    // Version numbers
    #define MAJOR_VERSION			245
    #define MINOR_VERSION			01
    
    ///////////////////////////
    // PROTOTYPES
    //////////////////////////
    /* Declaration of dv_fpga.c functions */
    int dv_fpga_open(struct inode *inode, struct file *filp);
    int dv_fpga_release(struct inode *inode, struct file *filp);
    ssize_t dv_fpga_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
    ssize_t dv_fpga_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos);
    static void dv_fpga_exit(void);
    static int dv_fpga_init(void);
    
    // Global pointer to the clock struct. We use this to start up the LPSoC (local power system on chip)
    // so our fpga peripheral has power going to it.
    static struct clk *g_clkptr = 0;
    static struct cdev cdev;
    
    // Structure that declares the usual file access functions
    static struct file_operations dv_fpga_fops = {
    	read: dv_fpga_read,
    	write: dv_fpga_write,
    	open: dv_fpga_open,
    	release: dv_fpga_release
    };
    
    // We will use a 1K buffer to store data
    static unsigned char * g_buf;
    static unsigned int g_bufcount = 0;
    
    
    static dev_t dev;
    static struct class_simple *fpga_class = NULL;
    struct device *fpga_dev;
    
    ////////////////////////////////////////////////////////////////////////////////////////
    struct fpga_fpga_device {
    	unsigned char opened;	/* state of the device */
    	struct semaphore sem;
    };
    ////////////////////////////////////////////////////////////////////////////////////////
    
    static int __init fpga_probe(struct device *device)
    {
    	fpga_dev = device;
    	return 0;
    }
    
    static int fpga_remove(struct device *device)
    {
    	return 0;
    }
    
    static void fpga_platform_release(struct device *device)
    {
    	/* This is called when the reference count goes to zero */
    }
    
    static struct device_driver fpga_driver = {
    	.name = "fpga",
    	.bus = &platform_bus_type,
    	.probe = fpga_probe,
    	.remove = fpga_remove,
    };
    static struct platform_device fpga_device = {
    	.name = "fpga",
    	.id = 0,
    	.dev = {
    		.release = fpga_platform_release,
    		}
    };
    
    //////////////////////////////////////////////////////////////
    static int dv_fpga_init(void) 
    {
    	int result;
    
    	result = alloc_chrdev_region(&dev, 0, 1, "fpga");
            if (result < 0) {
       //             dev_dbg(fpga_dev, "fpga: Module intialization failed. could not register character device\n");
                    return -ENODEV;
            } 
    	/* Initialize of character device */
    	cdev_init(&cdev, &dv_fpga_fops);
    	cdev.owner = THIS_MODULE;
    	cdev.ops = &dv_fpga_fops;
    
    	/* addding character device */
    	result = cdev_add(&cdev, dev, 1);
    
    	if (result) {
    		printk("adding fpga error no: %d ", result);
    		unregister_chrdev_region(dev, 1);
    		return result;
    	}
    ///////////////////////////////
    	/* Registering device */
    	result = register_chrdev(MAJOR_VERSION, "fpga", &dv_fpga_fops);
    	if (result < 0) 
    	{
    		printk("<1>dv_fpga: cannot obtain major number %d\n", MAJOR_VERSION);
    		return result;
    	}
    	/* register driver as a platform driver */
    	if (driver_register(&fpga_driver) != 0) {
    		printk("fpga_init: error in Registering driver\n");
    		cdev_del(&cdev);
    		return -EINVAL;
    	}
    
    	/* Register the drive as a platform device */
    	if (platform_device_register(&fpga_device) != 0) {
    		printk("fpga_init: error in Registering device\n");
    		driver_unregister(&fpga_driver);
    		unregister_chrdev(MAJOR_VERSION, "fpga");
    		cdev_del(&cdev);
    		return -EINVAL;
    	}
    
    	// Allocate space for the read buffer
    	g_buf = kmalloc(DATABUFFER_ALLOC, GFP_KERNEL); 
    	if (!g_buf) 
    	{ 
    		result = -ENOMEM;
    		dv_fpga_exit(); 
    		return result;
    	} 
    
    	printk("<1>Inserting fpga module\n"); 
    	return 0;
    }
    
    static void dv_fpga_exit(void) 
    {
    	/* Freeing the major number */
    	unregister_chrdev(MAJOR_VERSION, "fpga");
    
    	/* Freeing buffer memory */
    	if(g_buf)
    		kfree(g_buf);
    
    	if (g_clkptr) 
    		dv_fpga_release(0,0);
    
    	printk("<1>Removing fpga module\n");
    }
    
    
    // Called when a userspace program opens the file
    int dv_fpga_open(struct inode *inode, struct file *filp)
    {
    
    	return 0;
    }
    
    
    // Called when a userspace program closes the file
    int dv_fpga_release(struct inode *inode, struct file *filp)
    {
    
    	return 0;
    }
    
    
    // Reading from the fpga device
    ssize_t dv_fpga_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
    {
    	unsigned int 	control;
    
    	printk("enter dv_fpga_read \n");
    
    	for(j=0; j < 20; j++)
    	{
    
    		control = fpga_REG(AEMIFBASE + j );
    		printk("control = %x.\n", control);
    		udelay(4); 
    	}
    
    	return 0;
    }
    
    // Writing to the fpga device
    ssize_t dv_fpga_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
    {
    	unsigned int 	control;
    
    	printk("enter dv_fpga_write \n");
    
    	for(j=0; j < 20; j++)
    	{
    
    		fpga_REG(AEMIFBASE + j ) = control;
    
    		udelay(4); 
    	}
    
    	return 0;
    }
    
    MODULE_LICENSE("Dual BSD/GPL");
    MODULE_AUTHOR("serdar/Jammy Dane");
    module_init(dv_fpga_init);
    module_exit(dv_fpga_exit);
    
    Hi Richardson,

    1, I am using a custom board with DM368 and FPGA only, and there is no CPLD, the FPGA is connected to dm368 by emif interface directly.

    2, I have test your code you put on net, and it does works!!! I can read the value of the registers of FPGA .

    thank you very much.

    I have another questions:

    1, I want send lots of video data to FPGA, and the emif only can send the data 16bits or 8bits every time, I think the efficient is low, should I write a driver?

    2, my old two driver codes is as the the file loaded, help me for that.

    ///////////////////////////
    // changed by JAMMY at 2015.08.06
    //////////////////////////
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/delay.h>              // udelay()
    #include <linux/fs.h>                     // everything...
    #include <asm/uaccess.h>          // copy_from/to_user
    #include <linux/cdev.h>
    //#include <linux/devfs_fs_kernel.h>	/* for devfs */
    // Definition for fpga Base Address and the local Power or Sleep Controller LPSoC
    #include <mach/hardware.h> 
    #include <mach/clock.h>
    #include <linux/platform_device.h>
    #include <linux/clk.h>
    #include <linux/spinlock.h>
    #include <linux/proc_fs.h>
    #include <linux/sysctl.h>
    #include <linux/interrupt.h>
    #include <linux/device.h>
    #include <linux/irq.h>
    #include <asm/io.h>
    //#include <asm/arch/gio.h>
    ///////////////////////////
    // DEFINITIONS & GLOBALS
    //////////////////////////
    // Register definitions to control the fpga,refer to dm355 fpga referrence guide.pdf
    #define	AEMIFBASE			0x04000000
    #define EMIF_BASEADDR			0x01d10000
    #define FPGA_ADDR			0x04000000
    #define MODULE_NAME      		"davinci_fpga"
    #define FPGA_BUF			4096
    
    // Macro for accessing a memory location such as a register
    #define fpga_REG(reg)    		(*(volatile unsigned int *)IO_ADDRESS(reg))
    
    #define __REG(addr)   (*(volatile unsigned int *)IO_ADDRESS(addr))
    
    #define REG_PINMUX0     __REG(0x01c40000)
    #define REG_PINMUX1     __REG(0x01c40004)
    #define REG_PINMUX2     __REG(0x01c40008)
    #define REG_PINMUX3     __REG(0x01c4000c)
    #define REG_PINMUX4     __REG(0x01c40010)
    #define REG_FPGA	__REG(0x04000000)
    
    // Version numbers
    #define MAJOR_VERSION			205
    #define MINOR_VERSION			01
    
    ///////////////////////////
    // PROTOTYPES
    //////////////////////////
    /* Declaration of dv_fpga.c functions */
    int dv_fpga_open(struct inode *inode, struct file *filp);
    int dv_fpga_release(struct inode *inode, struct file *filp);
    ssize_t dv_fpga_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);
    ssize_t dv_fpga_read(struct file *filp, const char *buf, size_t count, loff_t *f_pos);
    static void dv_fpga_exit(void);
    static int dv_fpga_init(void);
    
    // Global pointer to the clock struct. We use this to start up the LPSoC (local power system on chip)
    // so our fpga peripheral has power going to it.
    static struct clk *g_clkptr = 0;
    static struct cdev cdev;
    
    // Structure that declares the usual file access functions
    static struct file_operations dv_fpga_fops = {
    	read: dv_fpga_read,
    	write: dv_fpga_write,
    	open: dv_fpga_open,
    	release: dv_fpga_release
    };
    
    typedef struct EMIF_device
    {
    	struct cdev cdev;
    	void * EMIF_vbase;
    	char * EMIFBaseBufRead;
    	char * EMIFBaseBufWrite;          
    } EMIF_DEV;
     
    int EMIF_devfs;
    EMIF_DEV * EMIF_dev;
    // We will use a 1K buffer to store data
    static unsigned char * g_buf;
    static unsigned int g_bufcount = 0;
    
    static dev_t dev;
    
    static void EMIF_setup_cdev(struct EMIF_device *dev,int index)
    {
      int err,devno=MKDEV(MAJOR_VERSION,index);
      cdev_init(&dev->cdev,&dv_fpga_fops);
      dev->cdev.owner =THIS_MODULE;
      dev->cdev.ops=&dv_fpga_fops;
     err = cdev_add(&dev->cdev, devno, 1);
     if(err)
    		printk(KERN_NOTICE "Error %d adding emif%d", err,index);
    }
    
    void emifinit()
    {
    	printk("%x.\n", REG_PINMUX2);
    	REG_PINMUX2 = 0x5A;
    	printk("----%x.\n", REG_PINMUX2);
    	unsigned long io_addr;
    	unsigned long emifa2cr,emifawccr;
    	//io_addr=IO_ADDRESS(EMIF_BASEADDR);  //设置基准地址,能否用IO_ADDRESS()?,换成动态映射是否更准确
    	io_addr=ioremap(EMIF_BASEADDR,0x100); 
    	emifa2cr=inl(io_addr+0x14)&0x00;
    	//emifa2cr=inl(EMIF_dev->EMIF_vbase+0x14)&0x00;
    	emifa2cr=emifa2cr |(0<<31)|(0<<30)|(2<<26)|(8<<20)|(5<<17)|(4<<13)|(14<<7)|(5<<4)|(6<<2)|(0<<0);
    	outl(emifa2cr,io_addr+0x14);
    	//outl(emifa2cr,EMIF_dev->EMIF_vbase+0x14);
    
    
    	emifawccr=inl(io_addr+0x04)&0x00;
    	//emifawccr=inl(EMIF_dev->EMIF_vbase+0x04)&0x00;
    	emifawccr=emifawccr|0x20000000;
    	outl(emifawccr,io_addr+0x04);
    	//outl(emifawccr,EMIF_dev->EMIF_vbase+0x04);
    }//设置两个寄存器的值//
    //////////////////////////////////////////////////////////////
    int __init dv_fpga_init(void) 
    {
    #if 0 
    	int result;
    	
    	result = register_chrdev (MAJOR_VERSION, MODULE_NAME, &dv_fpga_fops);
    
    	if (result)
    	{
    		printk ("davinci_fpga : can't get major number \n");
    		return result;
    	}
    
    	unsigned long io_addr;
    	unsigned long emifa2cr,emifawccr;
    	//io_addr=IO_ADDRESS(EMIF_BASEADDR);  //设置基准地址,能否用IO_ADDRESS()?,换成动态映射是否更准确
    	io_addr=ioremap(EMIF_BASEADDR,0x100); 
    	emifa2cr=inl(io_addr+0x14)&0x00;
    	//emifa2cr=inl(EMIF_dev->EMIF_vbase+0x14)&0x00;
    	emifa2cr=emifa2cr |(0<<31)|(0<<30)|(2<<26)|(8<<20)|(5<<17)|(4<<13)|(14<<7)|(5<<4)|(6<<2)|(0<<0);
    	outl(emifa2cr,io_addr+0x14);
    	//outl(emifa2cr,EMIF_dev->EMIF_vbase+0x14);
    
    
    	emifawccr=inl(io_addr+0x04)&0x00;
    	//emifawccr=inl(EMIF_dev->EMIF_vbase+0x04)&0x00;
    	emifawccr=emifawccr|0x20000000;
    	outl(emifawccr,io_addr+0x04);
    
    	printk("<1>Inserting %s module\n", MODULE_NAME); 
    	return 0;
    #else
    	printk(KERN_INFO "emif Driver Initialisation \n");
    	//EMIF_devfs = devfs_register(NULL,"EMIF",DEVFS_FL_DEFAULT,MAJOR_VERSION,0,S_IFCHR |S_IRUSR |S_IWUSR |S_IRGRP |S_IWGRP,&dv_fpga_fops,NULL);  //注册设备
    
    	//EMIF_devfs=register_chrdev(MAJOR_VERSION, "EMIF", &dv_fpga_fops);
    	dev_t devno=MKDEV(MAJOR_VERSION,0);   //分配设备号//
    	EMIF_devfs= register_chrdev_region(devno, 1, "EMIF");//注册设备
    	if (EMIF_devfs<0)
    	{
    		printk("EMIF devfs_register failed/n");
    		goto fail_devfs_register; 
    	}
    
    	EMIF_dev = kmalloc(sizeof (EMIF_DEV), GFP_KERNEL);  //申请分配空间,以存储设备信息
    	if (NULL==EMIF_dev)
    	{
    		printk("fail_malloc EMIF_dev/n");
    		goto fail_malloc;
    	}
    
    	memset(EMIF_dev, 0, sizeof (EMIF_DEV));   //分配空间的值全部填为零
    	EMIF_setup_cdev(EMIF_dev,0);   //注册结束
    
    	//EMIF_dev->EMIF_vbase=ioremap(FPGA_ADDR,0x100);  //地址空间映射
    
    	//if(NULL==request_region((unsigned int)EMIF_dev->EMIF_vbase,0x100,"EMIF"))   //使用IO必须先 请求以让内核知道欲访问IO端口,再做映射;返回一段资源结构,包含                                                                                 //start和end//
    	if(NULL==request_region(FPGA_ADDR,0x100,"EMIF")) 
    	{
    		printk("EMIF request_region failed/n");
    		goto fail_request_region;
    	}
    	else
    	{
    		EMIF_dev->EMIF_vbase=ioremap(FPGA_ADDR,0x100);   //基地址映射
    	
    	emifinit();
    
    	struct class *EMIFdev = class_create(THIS_MODULE, "EMIF");
    	device_create(EMIFdev,NULL, MKDEV(MAJOR_VERSION,0), NULL, "EMIF");
    	return 0;
    	}
    fail_request_region:
    	// iounmap(EMIF_dev->EMIF_vbase);
    	kfree(EMIF_dev);
    	fail_malloc:
    	//devfs_unregister(EMIF_devfs);
    	unregister_chrdev(MAJOR_VERSION, "EMIF");
    	fail_devfs_register:
    	return -1;
    #endif
    }
    
    void __exit dv_fpga_exit(void) 
    {
    #if 0
    	/* Freeing the major number */
    	unregister_chrdev(MAJOR_VERSION, MODULE_NAME);
    
    	/* Freeing buffer memory */
    	if(g_buf)
    		kfree(g_buf);
    
    	if (g_clkptr) 
    		dv_fpga_release(0,0);
    
    	printk("<1>Removing %s module.\n", MODULE_NAME);
    #else
    	iounmap(EMIF_dev->EMIF_vbase);
    	release_region(FPGA_ADDR,0x100);
    	//release_region((unsigned int)EMIF_dev->EMIF_vbase,0x100);
    	// iounmap(EMIF_dev->EMIF_vbase);
    	kfree(EMIF_dev);
    	unregister_chrdev(MAJOR_VERSION, "EMIF");
    	// devfs_unregister(EMIF_devfs);
    	device_destroy(EMIF_dev,MKDEV(MAJOR_VERSION,0));
    #endif
    }
    
    
    
    // Called when a userspace program opens the file
    int dv_fpga_open(struct inode *inode, struct file *filp)
    {
    	filp->private_data = EMIF_dev;//*private_data系统调用时用以保存状态信息*//
     	//MOD_INC_USE_COUNT;         //打开一次记录一次
    	// enable_irq(EMIF_INT);
    	return 0;
    }
    
    
    // Called when a userspace program closes the file
    int dv_fpga_release(struct inode *inode, struct file *filp)
    {
    
    	return 0;
    }
    
    
    // writing from the fpga device
    ssize_t dv_fpga_write(struct file *filp, char *buf, size_t count, loff_t *f_pos)
    {
    	unsigned int 	control;
    	unsigned int 	j;
    
    	printk("enter dv_fpga_write \n");
    #if 0
    	for(j=1; j < 20; j++)
    	{
    		control = fpga_REG(AEMIFBASE + j * 2);
    		printk("control = %x.\n", control);
    		udelay(40); 
    	}
    	return 0;
    #else
    	EMIF_DEV *EMIF_dev = filp->private_data;
    	int i;
    	size_t ret;
    	loff_t pos=*f_pos;
    	
    	//开辟驱动要使用的动态内存,分配连续的虚拟内存,与物理内存存在线性关系
    	EMIF_dev->EMIFBaseBufWrite=kmalloc(count, GFP_KERNEL);
    
    	if(!EMIF_dev->EMIFBaseBufWrite)
    		return -ENOMEM;
    
    	//成功返回为0,失败返回没被拷贝的字节数copy_from_user(用户空间地址,内核空间地址,拷贝的字节数)用户空间到内核空间的复制
    	if(!copy_from_user(EMIF_dev->EMIFBaseBufWrite,buf,count))  
    	{
    		for(i=0;i<count;i++)
    		{
    			outb((EMIF_dev->EMIFBaseBufWrite)[i],EMIF_dev->EMIF_vbase+(i<<3));   //  
    		}
    		kfree(EMIF_dev->EMIFBaseBufWrite);
    		ret=count;
    	}
    	else
    		ret=-EFAULT;
    
    	return ret;
    #endif
    }
    
    // reading to the fpga device
    ssize_t dv_fpga_read(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
    {
    	unsigned int 	control;
    	unsigned int 	j;
    
    	printk("enter dv_fpga_read \n");
    	printk("reg = %x.\n",REG_FPGA);
    #if 0
    	for(j=0; j < 20; j++)
    	{
    
    		fpga_REG(AEMIFBASE) = j;
    
    		udelay(40); 
    	}
    	return 0;
    #else
    	EMIF_DEV *dev = filp->private_data;
    	int i;
    	size_t ret ;
    	
    	//在内核空间分配内存,与物理地址存在线性关系,可以方便寻址,读取里面的操作//
    	dev->EMIFBaseBufRead=kmalloc(count, GFP_KERNEL);
    	if (!dev->EMIFBaseBufRead)
    		return -ENOMEM; 
    	
    	//成功返回为0,失败返回没被拷贝的字节数copy_to_user(用户空间地址,内核空间地址,拷贝的字节数)内核空间到用户空间的复制//
    	ret=copy_to_user(buf,dev->EMIFBaseBufRead,count)?-EFAULT : count;
    
    	return ret;
    #endif
    
    }
    
    MODULE_LICENSE("Dual BSD/GPL");
    MODULE_AUTHOR("serdar/Jammy Dane");
    module_init(dv_fpga_init);
    module_exit(dv_fpga_exit);
    

  • Hi Derek,

    1, I am using a custom board that the FPGA is connected dm368 with emif directly.

    2, I have test your code and it does work!!! I can read the value of the registers of EMIF, thank you revy much.

    3, I want transmit the video data using EMIF, I think I should write a driver, but I have no idea about it.

    4, my two wrong driver codes are as below, help me.

    ///////////////////////////
    // changed by Wugang at 2009.02.19
    //////////////////////////
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/delay.h>              // udelay()
    #include <linux/fs.h>                     // everything...
    #include <asm/uaccess.h>          // copy_from/to_user
    #include <linux/cdev.h>
    //#include <linux/devfs_fs_kernel.h>	/* for devfs */
    // Definition for fpga Base Address and the local Power or Sleep Controller LPSoC
    #include <mach/hardware.h> 
    #include <mach/clock.h>
    #include <linux/platform_device.h>
    #include <linux/clk.h>
    #include <linux/spinlock.h>
    #include <linux/proc_fs.h>
    #include <linux/sysctl.h>
    #include <linux/interrupt.h>
    #include <linux/device.h>
    #include <linux/irq.h>
    #include <asm/io.h>
    //#include <asm/arch/gio.h>
    ///////////////////////////
    // DEFINITIONS & GLOBALS
    //////////////////////////
    // Register definitions to control the fpga,refer to dm355 fpga referrence guide.pdf
    #define AEMIFBASE			0x04000000
    
    #define FPGA_BUF			4096
    
    // Macro for accessing a memory location such as a register
    #define fpga_REG(reg)    (*(int *__iomem) IO_ADDRESS(reg))
    
    // Version numbers
    #define MAJOR_VERSION			245
    #define MINOR_VERSION			01
    
    ///////////////////////////
    // PROTOTYPES
    //////////////////////////
    /* Declaration of dv_fpga.c functions */
    int dv_fpga_open(struct inode *inode, struct file *filp);
    int dv_fpga_release(struct inode *inode, struct file *filp);
    ssize_t dv_fpga_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
    ssize_t dv_fpga_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos);
    static void dv_fpga_exit(void);
    static int dv_fpga_init(void);
    
    // Global pointer to the clock struct. We use this to start up the LPSoC (local power system on chip)
    // so our fpga peripheral has power going to it.
    static struct clk *g_clkptr = 0;
    static struct cdev cdev;
    
    // Structure that declares the usual file access functions
    static struct file_operations dv_fpga_fops = {
    	read: dv_fpga_read,
    	write: dv_fpga_write,
    	open: dv_fpga_open,
    	release: dv_fpga_release
    };
    
    // We will use a 1K buffer to store data
    static unsigned char * g_buf;
    static unsigned int g_bufcount = 0;
    
    
    static dev_t dev;
    static struct class_simple *fpga_class = NULL;
    struct device *fpga_dev;
    
    ////////////////////////////////////////////////////////////////////////////////////////
    struct fpga_fpga_device {
    	unsigned char opened;	/* state of the device */
    	struct semaphore sem;
    };
    ////////////////////////////////////////////////////////////////////////////////////////
    
    static int __init fpga_probe(struct device *device)
    {
    	fpga_dev = device;
    	return 0;
    }
    
    static int fpga_remove(struct device *device)
    {
    	return 0;
    }
    
    static void fpga_platform_release(struct device *device)
    {
    	/* This is called when the reference count goes to zero */
    }
    
    static struct device_driver fpga_driver = {
    	.name = "fpga",
    	.bus = &platform_bus_type,
    	.probe = fpga_probe,
    	.remove = fpga_remove,
    };
    static struct platform_device fpga_device = {
    	.name = "fpga",
    	.id = 0,
    	.dev = {
    		.release = fpga_platform_release,
    		}
    };
    
    //////////////////////////////////////////////////////////////
    static int dv_fpga_init(void) 
    {
    	int result;
    
    	result = alloc_chrdev_region(&dev, 0, 1, "fpga");
            if (result < 0) {
       //             dev_dbg(fpga_dev, "fpga: Module intialization failed. could not register character device\n");
                    return -ENODEV;
            } 
    	/* Initialize of character device */
    	cdev_init(&cdev, &dv_fpga_fops);
    	cdev.owner = THIS_MODULE;
    	cdev.ops = &dv_fpga_fops;
    
    	/* addding character device */
    	result = cdev_add(&cdev, dev, 1);
    
    	if (result) {
    		printk("adding fpga error no: %d ", result);
    		unregister_chrdev_region(dev, 1);
    		return result;
    	}
    ///////////////////////////////
    	/* Registering device */
    	result = register_chrdev(MAJOR_VERSION, "fpga", &dv_fpga_fops);
    	if (result < 0) 
    	{
    		printk("<1>dv_fpga: cannot obtain major number %d\n", MAJOR_VERSION);
    		return result;
    	}
    	/* register driver as a platform driver */
    	if (driver_register(&fpga_driver) != 0) {
    		printk("fpga_init: error in Registering driver\n");
    		cdev_del(&cdev);
    		return -EINVAL;
    	}
    
    	/* Register the drive as a platform device */
    	if (platform_device_register(&fpga_device) != 0) {
    		printk("fpga_init: error in Registering device\n");
    		driver_unregister(&fpga_driver);
    		unregister_chrdev(MAJOR_VERSION, "fpga");
    		cdev_del(&cdev);
    		return -EINVAL;
    	}
    
    	// Allocate space for the read buffer
    	g_buf = kmalloc(DATABUFFER_ALLOC, GFP_KERNEL); 
    	if (!g_buf) 
    	{ 
    		result = -ENOMEM;
    		dv_fpga_exit(); 
    		return result;
    	} 
    
    	printk("<1>Inserting fpga module\n"); 
    	return 0;
    }
    
    static void dv_fpga_exit(void) 
    {
    	/* Freeing the major number */
    	unregister_chrdev(MAJOR_VERSION, "fpga");
    
    	/* Freeing buffer memory */
    	if(g_buf)
    		kfree(g_buf);
    
    	if (g_clkptr) 
    		dv_fpga_release(0,0);
    
    	printk("<1>Removing fpga module\n");
    }
    
    
    // Called when a userspace program opens the file
    int dv_fpga_open(struct inode *inode, struct file *filp)
    {
    
    	return 0;
    }
    
    
    // Called when a userspace program closes the file
    int dv_fpga_release(struct inode *inode, struct file *filp)
    {
    
    	return 0;
    }
    
    
    // Reading from the fpga device
    ssize_t dv_fpga_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
    {
    	unsigned int 	control;
    
    	printk("enter dv_fpga_read \n");
    
    	for(j=0; j < 20; j++)
    	{
    
    		control = fpga_REG(AEMIFBASE + j );
    		printk("control = %x.\n", control);
    		udelay(4); 
    	}
    
    	return 0;
    }
    
    // Writing to the fpga device
    ssize_t dv_fpga_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
    {
    	unsigned int 	control;
    
    	printk("enter dv_fpga_write \n");
    
    	for(j=0; j < 20; j++)
    	{
    
    		fpga_REG(AEMIFBASE + j ) = control;
    
    		udelay(4); 
    	}
    
    	return 0;
    }
    
    MODULE_LICENSE("Dual BSD/GPL");
    MODULE_AUTHOR("serdar/Jammy Dane");
    module_init(dv_fpga_init);
    module_exit(dv_fpga_exit);
    
    ///////////////////////////
    // changed by JAMMY at 2015.08.06
    //////////////////////////
    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/delay.h>              // udelay()
    #include <linux/fs.h>                     // everything...
    #include <asm/uaccess.h>          // copy_from/to_user
    #include <linux/cdev.h>
    //#include <linux/devfs_fs_kernel.h>	/* for devfs */
    // Definition for fpga Base Address and the local Power or Sleep Controller LPSoC
    #include <mach/hardware.h> 
    #include <mach/clock.h>
    #include <linux/platform_device.h>
    #include <linux/clk.h>
    #include <linux/spinlock.h>
    #include <linux/proc_fs.h>
    #include <linux/sysctl.h>
    #include <linux/interrupt.h>
    #include <linux/device.h>
    #include <linux/irq.h>
    #include <asm/io.h>
    //#include <asm/arch/gio.h>
    ///////////////////////////
    // DEFINITIONS & GLOBALS
    //////////////////////////
    // Register definitions to control the fpga,refer to dm355 fpga referrence guide.pdf
    #define	AEMIFBASE			0x04000000
    #define EMIF_BASEADDR			0x01d10000
    #define FPGA_ADDR			0x04000000
    #define MODULE_NAME      		"davinci_fpga"
    #define FPGA_BUF			4096
    
    // Macro for accessing a memory location such as a register
    #define fpga_REG(reg)    		(*(volatile unsigned int *)IO_ADDRESS(reg))
    
    #define __REG(addr)   (*(volatile unsigned int *)IO_ADDRESS(addr))
    
    #define REG_PINMUX0     __REG(0x01c40000)
    #define REG_PINMUX1     __REG(0x01c40004)
    #define REG_PINMUX2     __REG(0x01c40008)
    #define REG_PINMUX3     __REG(0x01c4000c)
    #define REG_PINMUX4     __REG(0x01c40010)
    #define REG_FPGA	__REG(0x04000000)
    
    // Version numbers
    #define MAJOR_VERSION			205
    #define MINOR_VERSION			01
    
    ///////////////////////////
    // PROTOTYPES
    //////////////////////////
    /* Declaration of dv_fpga.c functions */
    int dv_fpga_open(struct inode *inode, struct file *filp);
    int dv_fpga_release(struct inode *inode, struct file *filp);
    ssize_t dv_fpga_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);
    ssize_t dv_fpga_read(struct file *filp, const char *buf, size_t count, loff_t *f_pos);
    static void dv_fpga_exit(void);
    static int dv_fpga_init(void);
    
    // Global pointer to the clock struct. We use this to start up the LPSoC (local power system on chip)
    // so our fpga peripheral has power going to it.
    static struct clk *g_clkptr = 0;
    static struct cdev cdev;
    
    // Structure that declares the usual file access functions
    static struct file_operations dv_fpga_fops = {
    	read: dv_fpga_read,
    	write: dv_fpga_write,
    	open: dv_fpga_open,
    	release: dv_fpga_release
    };
    
    typedef struct EMIF_device
    {
    	struct cdev cdev;
    	void * EMIF_vbase;
    	char * EMIFBaseBufRead;
    	char * EMIFBaseBufWrite;          
    } EMIF_DEV;
     
    int EMIF_devfs;
    EMIF_DEV * EMIF_dev;
    // We will use a 1K buffer to store data
    static unsigned char * g_buf;
    static unsigned int g_bufcount = 0;
    
    static dev_t dev;
    
    static void EMIF_setup_cdev(struct EMIF_device *dev,int index)
    {
      int err,devno=MKDEV(MAJOR_VERSION,index);
      cdev_init(&dev->cdev,&dv_fpga_fops);
      dev->cdev.owner =THIS_MODULE;
      dev->cdev.ops=&dv_fpga_fops;
     err = cdev_add(&dev->cdev, devno, 1);
     if(err)
    		printk(KERN_NOTICE "Error %d adding emif%d", err,index);
    }
    
    void emifinit()
    {
    	printk("%x.\n", REG_PINMUX2);
    	REG_PINMUX2 = 0x5A;
    	printk("----%x.\n", REG_PINMUX2);
    	unsigned long io_addr;
    	unsigned long emifa2cr,emifawccr;
    	//io_addr=IO_ADDRESS(EMIF_BASEADDR);  //设置基准地址,能否用IO_ADDRESS()?,换成动态映射是否更准确
    	io_addr=ioremap(EMIF_BASEADDR,0x100); 
    	emifa2cr=inl(io_addr+0x14)&0x00;
    	//emifa2cr=inl(EMIF_dev->EMIF_vbase+0x14)&0x00;
    	emifa2cr=emifa2cr |(0<<31)|(0<<30)|(2<<26)|(8<<20)|(5<<17)|(4<<13)|(14<<7)|(5<<4)|(6<<2)|(0<<0);
    	outl(emifa2cr,io_addr+0x14);
    	//outl(emifa2cr,EMIF_dev->EMIF_vbase+0x14);
    
    
    	emifawccr=inl(io_addr+0x04)&0x00;
    	//emifawccr=inl(EMIF_dev->EMIF_vbase+0x04)&0x00;
    	emifawccr=emifawccr|0x20000000;
    	outl(emifawccr,io_addr+0x04);
    	//outl(emifawccr,EMIF_dev->EMIF_vbase+0x04);
    }//设置两个寄存器的值//
    //////////////////////////////////////////////////////////////
    int __init dv_fpga_init(void) 
    {
    #if 0 
    	int result;
    	
    	result = register_chrdev (MAJOR_VERSION, MODULE_NAME, &dv_fpga_fops);
    
    	if (result)
    	{
    		printk ("davinci_fpga : can't get major number \n");
    		return result;
    	}
    
    	unsigned long io_addr;
    	unsigned long emifa2cr,emifawccr;
    	//io_addr=IO_ADDRESS(EMIF_BASEADDR);  //设置基准地址,能否用IO_ADDRESS()?,换成动态映射是否更准确
    	io_addr=ioremap(EMIF_BASEADDR,0x100); 
    	emifa2cr=inl(io_addr+0x14)&0x00;
    	//emifa2cr=inl(EMIF_dev->EMIF_vbase+0x14)&0x00;
    	emifa2cr=emifa2cr |(0<<31)|(0<<30)|(2<<26)|(8<<20)|(5<<17)|(4<<13)|(14<<7)|(5<<4)|(6<<2)|(0<<0);
    	outl(emifa2cr,io_addr+0x14);
    	//outl(emifa2cr,EMIF_dev->EMIF_vbase+0x14);
    
    
    	emifawccr=inl(io_addr+0x04)&0x00;
    	//emifawccr=inl(EMIF_dev->EMIF_vbase+0x04)&0x00;
    	emifawccr=emifawccr|0x20000000;
    	outl(emifawccr,io_addr+0x04);
    
    	printk("<1>Inserting %s module\n", MODULE_NAME); 
    	return 0;
    #else
    	printk(KERN_INFO "emif Driver Initialisation \n");
    	//EMIF_devfs = devfs_register(NULL,"EMIF",DEVFS_FL_DEFAULT,MAJOR_VERSION,0,S_IFCHR |S_IRUSR |S_IWUSR |S_IRGRP |S_IWGRP,&dv_fpga_fops,NULL);  //注册设备
    
    	//EMIF_devfs=register_chrdev(MAJOR_VERSION, "EMIF", &dv_fpga_fops);
    	dev_t devno=MKDEV(MAJOR_VERSION,0);   //分配设备号//
    	EMIF_devfs= register_chrdev_region(devno, 1, "EMIF");//注册设备
    	if (EMIF_devfs<0)
    	{
    		printk("EMIF devfs_register failed/n");
    		goto fail_devfs_register; 
    	}
    
    	EMIF_dev = kmalloc(sizeof (EMIF_DEV), GFP_KERNEL);  //申请分配空间,以存储设备信息
    	if (NULL==EMIF_dev)
    	{
    		printk("fail_malloc EMIF_dev/n");
    		goto fail_malloc;
    	}
    
    	memset(EMIF_dev, 0, sizeof (EMIF_DEV));   //分配空间的值全部填为零
    	EMIF_setup_cdev(EMIF_dev,0);   //注册结束
    
    	//EMIF_dev->EMIF_vbase=ioremap(FPGA_ADDR,0x100);  //地址空间映射
    
    	//if(NULL==request_region((unsigned int)EMIF_dev->EMIF_vbase,0x100,"EMIF"))   //使用IO必须先 请求以让内核知道欲访问IO端口,再做映射;返回一段资源结构,包含                                                                                 //start和end//
    	if(NULL==request_region(FPGA_ADDR,0x100,"EMIF")) 
    	{
    		printk("EMIF request_region failed/n");
    		goto fail_request_region;
    	}
    	else
    	{
    		EMIF_dev->EMIF_vbase=ioremap(FPGA_ADDR,0x100);   //基地址映射
    	
    	emifinit();
    
    	struct class *EMIFdev = class_create(THIS_MODULE, "EMIF");
    	device_create(EMIFdev,NULL, MKDEV(MAJOR_VERSION,0), NULL, "EMIF");
    	return 0;
    	}
    fail_request_region:
    	// iounmap(EMIF_dev->EMIF_vbase);
    	kfree(EMIF_dev);
    	fail_malloc:
    	//devfs_unregister(EMIF_devfs);
    	unregister_chrdev(MAJOR_VERSION, "EMIF");
    	fail_devfs_register:
    	return -1;
    #endif
    }
    
    void __exit dv_fpga_exit(void) 
    {
    #if 0
    	/* Freeing the major number */
    	unregister_chrdev(MAJOR_VERSION, MODULE_NAME);
    
    	/* Freeing buffer memory */
    	if(g_buf)
    		kfree(g_buf);
    
    	if (g_clkptr) 
    		dv_fpga_release(0,0);
    
    	printk("<1>Removing %s module.\n", MODULE_NAME);
    #else
    	iounmap(EMIF_dev->EMIF_vbase);
    	release_region(FPGA_ADDR,0x100);
    	//release_region((unsigned int)EMIF_dev->EMIF_vbase,0x100);
    	// iounmap(EMIF_dev->EMIF_vbase);
    	kfree(EMIF_dev);
    	unregister_chrdev(MAJOR_VERSION, "EMIF");
    	// devfs_unregister(EMIF_devfs);
    	device_destroy(EMIF_dev,MKDEV(MAJOR_VERSION,0));
    #endif
    }
    
    
    
    // Called when a userspace program opens the file
    int dv_fpga_open(struct inode *inode, struct file *filp)
    {
    	filp->private_data = EMIF_dev;//*private_data系统调用时用以保存状态信息*//
     	//MOD_INC_USE_COUNT;         //打开一次记录一次
    	// enable_irq(EMIF_INT);
    	return 0;
    }
    
    
    // Called when a userspace program closes the file
    int dv_fpga_release(struct inode *inode, struct file *filp)
    {
    
    	return 0;
    }
    
    
    // writing from the fpga device
    ssize_t dv_fpga_write(struct file *filp, char *buf, size_t count, loff_t *f_pos)
    {
    	unsigned int 	control;
    	unsigned int 	j;
    
    	printk("enter dv_fpga_write \n");
    #if 0
    	for(j=1; j < 20; j++)
    	{
    		control = fpga_REG(AEMIFBASE + j * 2);
    		printk("control = %x.\n", control);
    		udelay(40); 
    	}
    	return 0;
    #else
    	EMIF_DEV *EMIF_dev = filp->private_data;
    	int i;
    	size_t ret;
    	loff_t pos=*f_pos;
    	
    	//开辟驱动要使用的动态内存,分配连续的虚拟内存,与物理内存存在线性关系
    	EMIF_dev->EMIFBaseBufWrite=kmalloc(count, GFP_KERNEL);
    
    	if(!EMIF_dev->EMIFBaseBufWrite)
    		return -ENOMEM;
    
    	//成功返回为0,失败返回没被拷贝的字节数copy_from_user(用户空间地址,内核空间地址,拷贝的字节数)用户空间到内核空间的复制
    	if(!copy_from_user(EMIF_dev->EMIFBaseBufWrite,buf,count))  
    	{
    		for(i=0;i<count;i++)
    		{
    			outb((EMIF_dev->EMIFBaseBufWrite)[i],EMIF_dev->EMIF_vbase+(i<<3));   //  
    		}
    		kfree(EMIF_dev->EMIFBaseBufWrite);
    		ret=count;
    	}
    	else
    		ret=-EFAULT;
    
    	return ret;
    #endif
    }
    
    // reading to the fpga device
    ssize_t dv_fpga_read(struct file *filp, const char *buf, size_t count, loff_t *f_pos)
    {
    	unsigned int 	control;
    	unsigned int 	j;
    
    	printk("enter dv_fpga_read \n");
    	printk("reg = %x.\n",REG_FPGA);
    #if 0
    	for(j=0; j < 20; j++)
    	{
    
    		fpga_REG(AEMIFBASE) = j;
    
    		udelay(40); 
    	}
    	return 0;
    #else
    	EMIF_DEV *dev = filp->private_data;
    	int i;
    	size_t ret ;
    	
    	//在内核空间分配内存,与物理地址存在线性关系,可以方便寻址,读取里面的操作//
    	dev->EMIFBaseBufRead=kmalloc(count, GFP_KERNEL);
    	if (!dev->EMIFBaseBufRead)
    		return -ENOMEM; 
    	
    	//成功返回为0,失败返回没被拷贝的字节数copy_to_user(用户空间地址,内核空间地址,拷贝的字节数)内核空间到用户空间的复制//
    	ret=copy_to_user(buf,dev->EMIFBaseBufRead,count)?-EFAULT : count;
    
    	return ret;
    #endif
    
    }
    
    MODULE_LICENSE("Dual BSD/GPL");
    MODULE_AUTHOR("serdar/Jammy Dane");
    module_init(dv_fpga_init);
    module_exit(dv_fpga_exit);
    

  • Hi Derek,
    I found a new problem, in my project, I set the value of 0x01D10014 address : 0xd466a31, which means using 16 bit normal mode, when I write a value like 0x5678 to 0x04000000 address which is maped to fpga 0 address, I only read 0x90 from the 0x04000000 address, why?

    my code is as below (refer to your code):

    *((unsigned short *) virt_addr) = 0x5678; // Virtual Address = 0x41389000 Actual Address = 0x4000000

    unsigned short readvalue = *((unsigned short *) virt_addr);
    printf("-----readvalue = %p sizeof(unsigned short) = %d.\n", readvalue, sizeof(unsigned short));
  • Hi Jammy,

    Have you tried debugging this from the FPGA side?  Are you using Xilinx or Altera FPGA?  Can you verify that when you write 0x5678 that the FPGA is actually receiving that value to write to FPGA register 0?  And how about the read cycle, do you see 0x5678 going out of the FPGA or 0x90 as you mentioned?

    Another question, have you tried using 8 bit mode as per my example?  And is that working ok?

    Also, did you memory map the addresses as per the example code I provided?  If the addresses aren't being mapped correctly, then maybe that's why we are getting invalid data.

    Derek

  • Hi Derek,

    Thanks for your reply.

    First, I should verify that when I send 0x5678 to FPGA from EMIF of DM368, the fpga can receive 0x78 on the data bus, and when I read the register, I can read the 0x78.

    The FPGA I used is Altera's FPGA, I only write data to the 0x04000000 namely the 0 address of the FPGA. When I write or read, I can see the occur of the CS, OE, and WE signal. So I think that the mamory map and the config of the address is just ok.

    When I use 8 bits mode by your code, the result is right, when I write a 0x12, I can read a 0x12.

    I think the 16bit mode did not work, I have set the A2CR register of EMIF to 16 bits mode by setting the ASIZE field to 1h, and I have set the Async EMIF Configuration (AECFG) Pin Mux Coding (AECFG register)to "101" by FPGA pull up, which enable the EM_A[14:0] and EM_D[15: 0].

    Is there something Iforget? Waiting for your further reply.

    Thank you very much.

    Jammy.

  • Hi Jammy, I'm not sure how much more help I can be with this, as I believe we only used 8 bit mode for our project.  It sounds like there is something missing from the configuration of 16 bit mode or the address is incorrect somehow.

    In 16-bit mode, if you write 0x5678, then you should expect to see 0x5678 on the databus. 

    You may have to get in touch with someone at TI who is more familiar with the EMIF configuration for DM368 than me.

    Hope what I've shared so far has been helpful.

    Kind Regards

    Derek

  • yeah, I will try it, thank you very much.
  • Hi Derek,

    I have configure the EMIF interface with 16bit mode successfully by setting the PINMUX2 registers.
    But there is a question: I think the mode I am using now is query which efficiency is low and the time delay is obvious.How can I use the EMIF interface with DMA mode?

    can U help me.

    thank you very much.