diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/fpga/Makefile | 1 | ||||
-rw-r--r-- | drivers/fpga/fpga.c | 225 | ||||
-rw-r--r-- | drivers/fpga/xilinx.c | 146 | ||||
-rw-r--r-- | drivers/fpga/zynqpl.c | 355 | ||||
-rw-r--r-- | drivers/i2c/Makefile | 1 | ||||
-rw-r--r-- | drivers/i2c/zynq_i2c.c | 306 | ||||
-rw-r--r-- | drivers/mmc/Makefile | 1 | ||||
-rw-r--r-- | drivers/mmc/zynq_sdhci.c | 40 | ||||
-rw-r--r-- | drivers/net/phy/marvell.c | 11 | ||||
-rw-r--r-- | drivers/net/zynq_gem.c | 199 |
10 files changed, 1108 insertions, 177 deletions
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index b48f623..0b51dcd 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -30,6 +30,7 @@ COBJS-y += fpga.o COBJS-$(CONFIG_FPGA_SPARTAN2) += spartan2.o COBJS-$(CONFIG_FPGA_SPARTAN3) += spartan3.o COBJS-$(CONFIG_FPGA_VIRTEX2) += virtex2.o +COBJS-$(CONFIG_FPGA_ZYNQPL) += zynqpl.o COBJS-$(CONFIG_FPGA_XILINX) += xilinx.o COBJS-$(CONFIG_FPGA_LATTICE) += ivm_core.o lattice.o ifdef CONFIG_FPGA_ALTERA diff --git a/drivers/fpga/fpga.c b/drivers/fpga/fpga.c index 26d2443..f70bff6 100644 --- a/drivers/fpga/fpga.c +++ b/drivers/fpga/fpga.c @@ -22,122 +22,99 @@ * */ -/* - * Generic FPGA support - */ +/* Generic FPGA support */ #include <common.h> /* core U-Boot definitions */ #include <xilinx.h> /* xilinx specific definitions */ #include <altera.h> /* altera specific definitions */ #include <lattice.h> -#if 0 -#define FPGA_DEBUG /* define FPGA_DEBUG to get debug messages */ -#endif - /* Local definitions */ #ifndef CONFIG_MAX_FPGA_DEVICES #define CONFIG_MAX_FPGA_DEVICES 5 #endif -/* Enable/Disable debug console messages */ -#ifdef FPGA_DEBUG -#define PRINTF(fmt,args...) printf (fmt ,##args) -#else -#define PRINTF(fmt,args...) -#endif - /* Local static data */ static int next_desc = FPGA_INVALID_DEVICE; static fpga_desc desc_table[CONFIG_MAX_FPGA_DEVICES]; -/* Local static functions */ -static __attribute__((__const__)) fpga_desc * __attribute__((__const__)) fpga_get_desc( int devnum ); -static __attribute__((__const__)) fpga_desc * __attribute__((__const__)) fpga_validate(int devnum, const void *buf, - size_t bsize, char *fn ); -static int fpga_dev_info( int devnum ); - - -/* ------------------------------------------------------------------------- */ - -/* fpga_no_sup +/* + * fpga_no_sup * 'no support' message function */ -static void fpga_no_sup( char *fn, char *msg ) +static void fpga_no_sup(char *fn, char *msg) { - if ( fn && msg ) { - printf( "%s: No support for %s.\n", fn, msg); - } else if ( msg ) { - printf( "No support for %s.\n", msg); - } else { - printf( "No FPGA suport!\n"); - } + if (fn && msg) + printf("%s: No support for %s.\n", fn, msg); + else if (msg) + printf("No support for %s.\n", msg); + else + printf("No FPGA suport!\n"); } /* fpga_get_desc * map a device number to a descriptor */ -static __attribute__((__const__)) fpga_desc * __attribute__((__const__)) fpga_get_desc( int devnum ) +static const fpga_desc *const fpga_get_desc(int devnum) { - fpga_desc *desc = (fpga_desc * )NULL; + fpga_desc *desc = (fpga_desc *)NULL; - if (( devnum >= 0 ) && (devnum < next_desc )) { + if ((devnum >= 0) && (devnum < next_desc)) { desc = &desc_table[devnum]; - PRINTF( "%s: found fpga descriptor #%d @ 0x%p\n", - __FUNCTION__, devnum, desc ); + debug("%s: found fpga descriptor #%d @ 0x%p\n", + __func__, devnum, desc); } return desc; } - -/* fpga_validate +/* + * fpga_validate * generic parameter checking code */ -static __attribute__((__const__)) fpga_desc * __attribute__((__const__)) fpga_validate(int devnum, const void *buf, - size_t bsize, char *fn ) +const fpga_desc *const fpga_validate(int devnum, const void *buf, + size_t bsize, char *fn) { - fpga_desc * desc = fpga_get_desc( devnum ); + const fpga_desc *desc = fpga_get_desc(devnum); - if ( !desc ) { - printf( "%s: Invalid device number %d\n", fn, devnum ); - } + if (!desc) + printf("%s: Invalid device number %d\n", fn, devnum); - if ( !buf ) { - printf( "%s: Null buffer.\n", fn ); + if (!buf) { + printf("%s: Null buffer.\n", fn); return (fpga_desc * const)NULL; } return desc; } - -/* fpga_dev_info +/* + * fpga_dev_info * generic multiplexing code */ -static int fpga_dev_info( int devnum ) +static int fpga_dev_info(int devnum) { - int ret_val = FPGA_FAIL; /* assume failure */ - const fpga_desc * const desc = fpga_get_desc( devnum ); + int ret_val = FPGA_FAIL; /* assume failure */ + const fpga_desc * const desc = fpga_get_desc(devnum); - if ( desc ) { - PRINTF( "%s: Device Descriptor @ 0x%p\n", - __FUNCTION__, desc->devdesc ); + if (desc) { + debug("%s: Device Descriptor @ 0x%p\n", + __func__, desc->devdesc); - switch ( desc->devtype ) { + switch (desc->devtype) { case fpga_xilinx: #if defined(CONFIG_FPGA_XILINX) - printf( "Xilinx Device\nDescriptor @ 0x%p\n", desc ); - ret_val = xilinx_info( desc->devdesc ); + printf("Xilinx Device\nDescriptor @ 0x%p\n", desc); + ret_val = xilinx_info(desc->devdesc); #else - fpga_no_sup( (char *)__FUNCTION__, "Xilinx devices" ); + fpga_no_sup((char *)__func__, "Xilinx devices"); #endif break; case fpga_altera: #if defined(CONFIG_FPGA_ALTERA) - printf( "Altera Device\nDescriptor @ 0x%p\n", desc ); - ret_val = altera_info( desc->devdesc ); + printf("Altera Device\nDescriptor @ 0x%p\n", desc); + ret_val = altera_info(desc->devdesc); #else - fpga_no_sup( (char *)__FUNCTION__, "Altera devices" ); + fpga_no_sup((char *)__func__, "Altera devices"); #endif break; case fpga_lattice: @@ -145,171 +122,183 @@ static int fpga_dev_info( int devnum ) printf("Lattice Device\nDescriptor @ 0x%p\n", desc); ret_val = lattice_info(desc->devdesc); #else - fpga_no_sup( (char *)__FUNCTION__, "Lattice devices" ); + fpga_no_sup((char *)__func__, "Lattice devices"); #endif break; default: - printf( "%s: Invalid or unsupported device type %d\n", - __FUNCTION__, desc->devtype ); + printf("%s: Invalid or unsupported device type %d\n", + __func__, desc->devtype); } } else { - printf( "%s: Invalid device number %d\n", - __FUNCTION__, devnum ); + printf("%s: Invalid device number %d\n", __func__, devnum); } return ret_val; } - -/* ------------------------------------------------------------------------- */ -/* fgpa_init is usually called from misc_init_r() and MUST be called +/* + * fgpa_init is usually called from misc_init_r() and MUST be called * before any of the other fpga functions are used. */ void fpga_init(void) { next_desc = 0; - memset( desc_table, 0, sizeof(desc_table)); + memset(desc_table, 0, sizeof(desc_table)); - PRINTF( "%s: CONFIG_FPGA = 0x%x\n", __FUNCTION__, CONFIG_FPGA ); + debug("%s\n", __func__); } -/* fpga_count +/* + * fpga_count * Basic interface function to get the current number of devices available. */ -int fpga_count( void ) +int fpga_count(void) { return next_desc; } -/* fpga_add +/* + * fpga_add * Add the device descriptor to the device table. */ -int fpga_add( fpga_type devtype, void *desc ) +int fpga_add(fpga_type devtype, void *desc) { int devnum = FPGA_INVALID_DEVICE; - if ( next_desc < 0 ) { - printf( "%s: FPGA support not initialized!\n", __FUNCTION__ ); - } else if (( devtype > fpga_min_type ) && ( devtype < fpga_undefined )) { - if ( desc ) { - if ( next_desc < CONFIG_MAX_FPGA_DEVICES ) { + if (next_desc < 0) { + printf("%s: FPGA support not initialized!\n", __func__); + } else if ((devtype > fpga_min_type) && (devtype < fpga_undefined)) { + if (desc) { + if (next_desc < CONFIG_MAX_FPGA_DEVICES) { devnum = next_desc; desc_table[next_desc].devtype = devtype; desc_table[next_desc++].devdesc = desc; } else { - printf( "%s: Exceeded Max FPGA device count\n", __FUNCTION__ ); + printf("%s: Exceeded Max FPGA device count\n", + __func__); } } else { - printf( "%s: NULL device descriptor\n", __FUNCTION__ ); + printf("%s: NULL device descriptor\n", __func__); } } else { - printf( "%s: Unsupported FPGA type %d\n", __FUNCTION__, devtype ); + printf("%s: Unsupported FPGA type %d\n", __func__, devtype); } return devnum; } /* - * Generic multiplexing code + * Convert bitstream data and load into the fpga + */ +int __weak fpga_loadbitstream(int devnum, char *fpgadata, size_t size) +{ + printf("Bitstream support not implemented for this FPGA device\n"); + return FPGA_FAIL; +} + +/* + * Generic multiplexing code */ int fpga_load(int devnum, const void *buf, size_t bsize) { int ret_val = FPGA_FAIL; /* assume failure */ - fpga_desc * desc = fpga_validate( devnum, buf, bsize, (char *)__FUNCTION__ ); + const fpga_desc *desc = fpga_validate(devnum, buf, bsize, + (char *)__func__); - if ( desc ) { - switch ( desc->devtype ) { + if (desc) { + switch (desc->devtype) { case fpga_xilinx: #if defined(CONFIG_FPGA_XILINX) - ret_val = xilinx_load( desc->devdesc, buf, bsize ); + ret_val = xilinx_load(desc->devdesc, buf, bsize); #else - fpga_no_sup( (char *)__FUNCTION__, "Xilinx devices" ); + fpga_no_sup((char *)__func__, "Xilinx devices"); #endif break; case fpga_altera: #if defined(CONFIG_FPGA_ALTERA) - ret_val = altera_load( desc->devdesc, buf, bsize ); + ret_val = altera_load(desc->devdesc, buf, bsize); #else - fpga_no_sup( (char *)__FUNCTION__, "Altera devices" ); + fpga_no_sup((char *)__func__, "Altera devices"); #endif break; case fpga_lattice: #if defined(CONFIG_FPGA_LATTICE) ret_val = lattice_load(desc->devdesc, buf, bsize); #else - fpga_no_sup( (char *)__FUNCTION__, "Lattice devices" ); + fpga_no_sup((char *)__func__, "Lattice devices"); #endif break; default: - printf( "%s: Invalid or unsupported device type %d\n", - __FUNCTION__, desc->devtype ); + printf("%s: Invalid or unsupported device type %d\n", + __func__, desc->devtype); } } return ret_val; } -/* fpga_dump +/* + * fpga_dump * generic multiplexing code */ int fpga_dump(int devnum, const void *buf, size_t bsize) { int ret_val = FPGA_FAIL; /* assume failure */ - fpga_desc * desc = fpga_validate( devnum, buf, bsize, (char *)__FUNCTION__ ); + const fpga_desc *desc = fpga_validate(devnum, buf, bsize, + (char *)__func__); - if ( desc ) { - switch ( desc->devtype ) { + if (desc) { + switch (desc->devtype) { case fpga_xilinx: #if defined(CONFIG_FPGA_XILINX) - ret_val = xilinx_dump( desc->devdesc, buf, bsize ); + ret_val = xilinx_dump(desc->devdesc, buf, bsize); #else - fpga_no_sup( (char *)__FUNCTION__, "Xilinx devices" ); + fpga_no_sup((char *)__func__, "Xilinx devices"); #endif break; case fpga_altera: #if defined(CONFIG_FPGA_ALTERA) - ret_val = altera_dump( desc->devdesc, buf, bsize ); + ret_val = altera_dump(desc->devdesc, buf, bsize); #else - fpga_no_sup( (char *)__FUNCTION__, "Altera devices" ); + fpga_no_sup((char *)__func__, "Altera devices"); #endif break; case fpga_lattice: #if defined(CONFIG_FPGA_LATTICE) ret_val = lattice_dump(desc->devdesc, buf, bsize); #else - fpga_no_sup( (char *)__FUNCTION__, "Lattice devices" ); + fpga_no_sup((char *)__func__, "Lattice devices"); #endif break; default: - printf( "%s: Invalid or unsupported device type %d\n", - __FUNCTION__, desc->devtype ); + printf("%s: Invalid or unsupported device type %d\n", + __func__, desc->devtype); } } return ret_val; } - -/* fpga_info +/* + * fpga_info * front end to fpga_dev_info. If devnum is invalid, report on all * available devices. */ -int fpga_info( int devnum ) +int fpga_info(int devnum) { - if ( devnum == FPGA_INVALID_DEVICE ) { - if ( next_desc > 0 ) { + if (devnum == FPGA_INVALID_DEVICE) { + if (next_desc > 0) { int dev; - for ( dev = 0; dev < next_desc; dev++ ) { - fpga_dev_info( dev ); - } + for (dev = 0; dev < next_desc; dev++) + fpga_dev_info(dev); + return FPGA_SUCCESS; } else { - printf( "%s: No FPGA devices available.\n", __FUNCTION__ ); + printf("%s: No FPGA devices available.\n", __func__); return FPGA_FAIL; } } - else return fpga_dev_info( devnum ); -} -/* ------------------------------------------------------------------------- */ + return fpga_dev_info(devnum); +} diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c index 32787b2..49e9437 100644 --- a/drivers/fpga/xilinx.c +++ b/drivers/fpga/xilinx.c @@ -1,4 +1,6 @@ /* + * (C) Copyright 2012-2013, Xilinx, Michal Simek + * * (C) Copyright 2002 * Rich Ireland, Enterasys Networks, rireland@enterasys.com. * Keith Outwater, keith_outwater@mvis.com @@ -28,9 +30,11 @@ */ #include <common.h> +#include <fpga.h> #include <virtex2.h> #include <spartan2.h> #include <spartan3.h> +#include <zynqpl.h> #if 0 #define FPGA_DEBUG @@ -48,6 +52,112 @@ static int xilinx_validate (Xilinx_desc * desc, char *fn); /* ------------------------------------------------------------------------- */ +int fpga_loadbitstream(int devnum, char *fpgadata, size_t size) +{ + unsigned int length; + unsigned int swapsize; + char buffer[80]; + unsigned char *dataptr; + unsigned int i; + const fpga_desc *desc; + Xilinx_desc *xdesc; + + dataptr = (unsigned char *)fpgadata; + /* Find out fpga_description */ + desc = fpga_validate(devnum, dataptr, 0, (char *)__func__); + /* Assign xilinx device description */ + xdesc = desc->devdesc; + + /* skip the first bytes of the bitsteam, their meaning is unknown */ + length = (*dataptr << 8) + *(dataptr + 1); + dataptr += 2; + dataptr += length; + + /* get design name (identifier, length, string) */ + length = (*dataptr << 8) + *(dataptr + 1); + dataptr += 2; + if (*dataptr++ != 0x61) { + debug("%s: Design name id not recognized in bitstream\n", + __func__); + return FPGA_FAIL; + } + + length = (*dataptr << 8) + *(dataptr + 1); + dataptr += 2; + for (i = 0; i < length; i++) + buffer[i] = *dataptr++; + + printf(" design filename = \"%s\"\n", buffer); + + /* get part number (identifier, length, string) */ + if (*dataptr++ != 0x62) { + printf("%s: Part number id not recognized in bitstream\n", + __func__); + return FPGA_FAIL; + } + + length = (*dataptr << 8) + *(dataptr + 1); + dataptr += 2; + for (i = 0; i < length; i++) + buffer[i] = *dataptr++; + + if (xdesc->name) { + i = strncmp(buffer, xdesc->name, strlen(xdesc->name)); + if (i) { + printf("%s: Wrong bitstream ID for this device\n", + __func__); + printf("%s: Bitstream ID %s, current device ID %d/%s\n", + __func__, buffer, devnum, xdesc->name); + return FPGA_FAIL; + } + } else { + printf("%s: Please fill correct device ID to Xilinx_desc\n", + __func__); + } + printf(" part number = \"%s\"\n", buffer); + + /* get date (identifier, length, string) */ + if (*dataptr++ != 0x63) { + printf("%s: Date identifier not recognized in bitstream\n", + __func__); + return FPGA_FAIL; + } + + length = (*dataptr << 8) + *(dataptr+1); + dataptr += 2; + for (i = 0; i < length; i++) + buffer[i] = *dataptr++; + printf(" date = \"%s\"\n", buffer); + + /* get time (identifier, length, string) */ + if (*dataptr++ != 0x64) { + printf("%s: Time identifier not recognized in bitstream\n", + __func__); + return FPGA_FAIL; + } + + length = (*dataptr << 8) + *(dataptr+1); + dataptr += 2; + for (i = 0; i < length; i++) + buffer[i] = *dataptr++; + printf(" time = \"%s\"\n", buffer); + + /* get fpga data length (identifier, length) */ + if (*dataptr++ != 0x65) { + printf("%s: Data length id not recognized in bitstream\n", + __func__); + return FPGA_FAIL; + } + swapsize = ((unsigned int) *dataptr << 24) + + ((unsigned int) *(dataptr + 1) << 16) + + ((unsigned int) *(dataptr + 2) << 8) + + ((unsigned int) *(dataptr + 3)); + dataptr += 4; + printf(" bytes in bitstream = %d\n", swapsize); + + return fpga_load(devnum, dataptr, swapsize); +} + int xilinx_load(Xilinx_desc *desc, const void *buf, size_t bsize) { int ret_val = FPGA_FAIL; /* assume a failure */ @@ -86,6 +196,16 @@ int xilinx_load(Xilinx_desc *desc, const void *buf, size_t bsize) __FUNCTION__); #endif break; + case xilinx_zynq: +#if defined(CONFIG_FPGA_ZYNQPL) + PRINTF("%s: Launching the Zynq PL Loader...\n", + __func__); + ret_val = zynq_load(desc, buf, bsize); +#else + printf("%s: No support for Zynq devices.\n", + __func__); +#endif + break; default: printf ("%s: Unsupported family type, %d\n", @@ -133,6 +253,16 @@ int xilinx_dump(Xilinx_desc *desc, const void *buf, size_t bsize) __FUNCTION__); #endif break; + case xilinx_zynq: +#if defined(CONFIG_FPGA_ZYNQPL) + PRINTF("%s: Launching the Zynq PL Reader...\n", + __func__); + ret_val = zynq_dump(desc, buf, bsize); +#else + printf("%s: No support for Zynq devices.\n", + __func__); +#endif + break; default: printf ("%s: Unsupported family type, %d\n", @@ -158,6 +288,9 @@ int xilinx_info (Xilinx_desc * desc) case Xilinx_Virtex2: printf ("Virtex-II\n"); break; + case xilinx_zynq: + printf("Zynq PL\n"); + break; /* Add new family types here */ default: printf ("Unknown family type, %d\n", desc->family); @@ -183,6 +316,9 @@ int xilinx_info (Xilinx_desc * desc) case master_selectmap: printf ("Master SelectMap Mode\n"); break; + case devcfg: + printf("Device configuration interface (Zynq)\n"); + break; /* Add new interface types here */ default: printf ("Unsupported interface type, %d\n", desc->iface); @@ -191,6 +327,8 @@ int xilinx_info (Xilinx_desc * desc) printf ("Device Size: \t%d bytes\n" "Cookie: \t0x%x (%d)\n", desc->size, desc->cookie, desc->cookie); + if (desc->name) + printf("Device name: \t%s\n", desc->name); if (desc->iface_fns) { printf ("Device Function Table @ 0x%p\n", desc->iface_fns); @@ -222,6 +360,14 @@ int xilinx_info (Xilinx_desc * desc) __FUNCTION__); #endif break; + case xilinx_zynq: +#if defined(CONFIG_FPGA_ZYNQPL) + zynq_info(desc); +#else + /* just in case */ + printf("%s: No support for Zynq devices.\n", + __func__); +#endif /* Add new family types here */ default: /* we don't need a message here - we give one up above */ diff --git a/drivers/fpga/zynqpl.c b/drivers/fpga/zynqpl.c new file mode 100644 index 0000000..8feccde --- /dev/null +++ b/drivers/fpga/zynqpl.c @@ -0,0 +1,355 @@ +/* + * (C) Copyright 2012-2013, Xilinx, Michal Simek + * + * (C) Copyright 2012 + * Joe Hershberger <joe.hershberger@ni.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <zynqpl.h> +#include <asm/arch/hardware.h> +#include <asm/arch/sys_proto.h> + +#define DEVCFG_CTRL_PCFG_PROG_B 0x40000000 +#define DEVCFG_ISR_FATAL_ERROR_MASK 0x00740040 +#define DEVCFG_ISR_ERROR_FLAGS_MASK 0x00340840 +#define DEVCFG_ISR_RX_FIFO_OV 0x00040000 +#define DEVCFG_ISR_DMA_DONE 0x00002000 +#define DEVCFG_ISR_PCFG_DONE 0x00000004 +#define DEVCFG_STATUS_DMA_CMD_Q_F 0x80000000 +#define DEVCFG_STATUS_DMA_CMD_Q_E 0x40000000 +#define DEVCFG_STATUS_DMA_DONE_CNT_MASK 0x30000000 +#define DEVCFG_STATUS_PCFG_INIT 0x00000010 +#define DEVCFG_MCTRL_RFIFO_FLUSH 0x00000002 +#define DEVCFG_MCTRL_WFIFO_FLUSH 0x00000001 + +#ifndef CONFIG_SYS_FPGA_WAIT +#define CONFIG_SYS_FPGA_WAIT CONFIG_SYS_HZ/100 /* 10 ms */ +#endif + +#ifndef CONFIG_SYS_FPGA_PROG_TIME +#define CONFIG_SYS_FPGA_PROG_TIME CONFIG_SYS_HZ /* 1 s */ +#endif + +int zynq_info(Xilinx_desc *desc) +{ + return FPGA_SUCCESS; +} + +#define DUMMY_WORD 0xffffffff + +/* Xilinx binary format header */ +static const u32 bin_format[] = { + DUMMY_WORD, /* Dummy words */ + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + DUMMY_WORD, + 0x000000bb, /* Sync word */ + 0x11220044, /* Sync word */ + DUMMY_WORD, + DUMMY_WORD, + 0xaa995566, /* Sync word */ +}; + +#define SWAP_NO 1 +#define SWAP_DONE 2 + +/* + * Load the whole word from unaligned buffer + * Keep in your mind that it is byte loading on little-endian system + */ +static u32 load_word(const void *buf, u32 swap) +{ + u32 word = 0; + u8 *bitc = (u8 *)buf; + int p; + + if (swap == SWAP_NO) { + for (p = 0; p < 4; p++) { + word <<= 8; + word |= bitc[p]; + } + } else { + for (p = 3; p >= 0; p--) { + word <<= 8; + word |= bitc[p]; + } + } + + return word; +} + +static u32 check_header(const void *buf) +{ + u32 i, pattern; + int swap = SWAP_NO; + u32 *test = (u32 *)buf; + + debug("%s: Let's check bitstream header\n", __func__); + + /* Checking that passing bin is not a bitstream */ + for (i = 0; i < ARRAY_SIZE(bin_format); i++) { + pattern = load_word(&test[i], swap); + + /* + * Bitstreams in binary format are swapped + * compare to regular bistream. + * Do not swap dummy word but if swap is done assume + * that parsing buffer is binary format + */ + if ((__swab32(pattern) != DUMMY_WORD) && + (__swab32(pattern) == bin_format[i])) { + pattern = __swab32(pattern); + swap = SWAP_DONE; + debug("%s: data swapped - let's swap\n", __func__); + } + + debug("%s: %d/%x: pattern %x/%x bin_format\n", __func__, i, + (u32)&test[i], pattern, bin_format[i]); + if (pattern != bin_format[i]) { + debug("%s: Bitstream is not recognized\n", __func__); + return 0; + } + } + debug("%s: Found bitstream header at %x %s swapinng\n", __func__, + (u32)buf, swap == SWAP_NO ? "without" : "with"); + + return swap; +} + +static void *check_data(u8 *buf, size_t bsize, u32 *swap) +{ + u32 word, p = 0; /* possition */ + + /* Because buf doesn't need to be aligned let's read it by chars */ + for (p = 0; p < bsize; p++) { + word = load_word(&buf[p], SWAP_NO); + debug("%s: word %x %x/%x\n", __func__, word, p, (u32)&buf[p]); + + /* Find the first bitstream dummy word */ + if (word == DUMMY_WORD) { + debug("%s: Found dummy word at position %x/%x\n", + __func__, p, (u32)&buf[p]); + *swap = check_header(&buf[p]); + if (*swap) { + /* FIXME add full bitstream checking here */ + return &buf[p]; + } + } + /* Loop can be huge - support CTRL + C */ + if (ctrlc()) + return 0; + } + return 0; +} + + +int zynq_load(Xilinx_desc *desc, const void *buf, size_t bsize) +{ + unsigned long ts; /* Timestamp */ + u32 partialbit = 0; + u32 i, control, isr_status, status, swap, diff; + u32 *buf_start; + + /* Detect if we are going working with partial or full bitstream */ + if (bsize != desc->size) { + printf("%s: Working with partial bitstream\n", __func__); + partialbit = 1; + } + + buf_start = check_data((u8 *)buf, bsize, &swap); + if (!buf_start) + return FPGA_FAIL; + + /* Check if data is postpone from start */ + diff = (u32)buf_start - (u32)buf; + if (diff) { + printf("%s: Bitstream is not validated yet (diff %x)\n", + __func__, diff); + return FPGA_FAIL; + } + + if ((u32)buf_start & 0x3) { + u32 *new_buf = (u32 *)((u32)buf & ~0x3); + + printf("%s: Align buffer at %x to %x(swap %d)\n", __func__, + (u32)buf_start, (u32)new_buf, swap); + + for (i = 0; i < (bsize/4); i++) + new_buf[i] = load_word(&buf_start[i], swap); + + swap = SWAP_DONE; + buf = new_buf; + } else if (swap != SWAP_DONE) { + /* For bitstream which are aligned */ + u32 *new_buf = (u32 *)buf; + + printf("%s: Bitstream is not swapped(%d) - swap it\n", __func__, + swap); + + for (i = 0; i < (bsize/4); i++) + new_buf[i] = load_word(&buf_start[i], swap); + + swap = SWAP_DONE; + } + + if (!partialbit) { + zynq_slcr_devcfg_disable(); + + /* Setting PCFG_PROG_B signal to high */ + control = readl(&devcfg_base->ctrl); + writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl); + /* Setting PCFG_PROG_B signal to low */ + writel(control & ~DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl); + + /* Polling the PCAP_INIT status for Reset */ + ts = get_timer(0); + while (readl(&devcfg_base->status) & DEVCFG_STATUS_PCFG_INIT) { + if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) { + printf("%s: Timeout wait for INIT to clear\n", + __func__); + return FPGA_FAIL; + } + } + + /* Setting PCFG_PROG_B signal to high */ + writel(control | DEVCFG_CTRL_PCFG_PROG_B, &devcfg_base->ctrl); + + /* Polling the PCAP_INIT status for Set */ + ts = get_timer(0); + while (!(readl(&devcfg_base->status) & + DEVCFG_STATUS_PCFG_INIT)) { + if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) { + printf("%s: Timeout wait for INIT to set\n", + __func__); + return FPGA_FAIL; + } + } + } + + isr_status = readl(&devcfg_base->int_sts); + + /* Clear it all, so if Boot ROM comes back, it can proceed */ + writel(0xFFFFFFFF, &devcfg_base->int_sts); + + if (isr_status & DEVCFG_ISR_FATAL_ERROR_MASK) { + debug("%s: Fatal errors in PCAP 0x%X\n", __func__, isr_status); + + /* If RX FIFO overflow, need to flush RX FIFO first */ + if (isr_status & DEVCFG_ISR_RX_FIFO_OV) { + writel(DEVCFG_MCTRL_RFIFO_FLUSH, &devcfg_base->mctrl); + writel(0xFFFFFFFF, &devcfg_base->int_sts); + } + return FPGA_FAIL; + } + + status = readl(&devcfg_base->status); + + debug("%s: Status = 0x%08X\n", __func__, status); + + if (status & DEVCFG_STATUS_DMA_CMD_Q_F) { + debug("%s: Error: device busy\n", __func__); + return FPGA_FAIL; + } + + debug("%s: Device ready\n", __func__); + + if (!(status & DEVCFG_STATUS_DMA_CMD_Q_E)) { + if (!(readl(&devcfg_base->int_sts) & DEVCFG_ISR_DMA_DONE)) { + /* Error state, transfer cannot occur */ + debug("%s: ISR indicates error\n", __func__); + return FPGA_FAIL; + } else { + /* Clear out the status */ + writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts); + } + } + + if (status & DEVCFG_STATUS_DMA_DONE_CNT_MASK) { + /* Clear the count of completed DMA transfers */ + writel(DEVCFG_STATUS_DMA_DONE_CNT_MASK, &devcfg_base->status); + } + + debug("%s: Source = 0x%08X\n", __func__, (u32)buf); + debug("%s: Size = %zu\n", __func__, bsize); + + /* Set up the transfer */ + writel((u32)buf | 1, &devcfg_base->dma_src_addr); + writel(0xFFFFFFFF, &devcfg_base->dma_dst_addr); + writel(bsize >> 2, &devcfg_base->dma_src_len); + writel(0, &devcfg_base->dma_dst_len); + + isr_status = readl(&devcfg_base->int_sts); + + /* Polling the PCAP_INIT status for Set */ + ts = get_timer(0); + while (!(isr_status & DEVCFG_ISR_DMA_DONE)) { + if (isr_status & DEVCFG_ISR_ERROR_FLAGS_MASK) { + debug("%s: Error: isr = 0x%08X\n", __func__, + isr_status); + debug("%s: Write count = 0x%08X\n", __func__, + readl(&devcfg_base->write_count)); + debug("%s: Read count = 0x%08X\n", __func__, + readl(&devcfg_base->read_count)); + + return FPGA_FAIL; + } + if (get_timer(ts) > CONFIG_SYS_FPGA_PROG_TIME) { + printf("%s: Timeout wait for DMA to complete\n", + __func__); + return FPGA_FAIL; + } + isr_status = readl(&devcfg_base->int_sts); + } + + debug("%s: DMA transfer is done\n", __func__); + + /* Check FPGA configuration completion */ + ts = get_timer(0); + while (!(isr_status & DEVCFG_ISR_PCFG_DONE)) { + if (get_timer(ts) > CONFIG_SYS_FPGA_WAIT) { + printf("%s: Timeout wait for FPGA to config\n", + __func__); + return FPGA_FAIL; + } + isr_status = readl(&devcfg_base->int_sts); + } + + debug("%s: FPGA config done\n", __func__); + + /* Clear out the DMA status */ + writel(DEVCFG_ISR_DMA_DONE, &devcfg_base->int_sts); + + if (!partialbit) + zynq_slcr_devcfg_enable(); + + return FPGA_SUCCESS; +} + +int zynq_dump(Xilinx_desc *desc, const void *buf, size_t bsize) +{ + return FPGA_FAIL; +} diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 5dbdbe3..72e85a3 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -46,6 +46,7 @@ COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o COBJS-$(CONFIG_SH_I2C) += sh_i2c.o COBJS-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o +COBJS-$(CONFIG_ZYNQ_I2C) += zynq_i2c.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/i2c/zynq_i2c.c b/drivers/i2c/zynq_i2c.c new file mode 100644 index 0000000..ec49660 --- /dev/null +++ b/drivers/i2c/zynq_i2c.c @@ -0,0 +1,306 @@ +/* + * Driver for the Zynq-7000 PS I2C controller + * IP from Cadence (ID T-CS-PE-0007-100, Version R1p10f2) + * + * Author: Joe Hershberger <joe.hershberger@ni.com> + * Copyright (c) 2012 Joe Hershberger. + * + * Copyright (c) 2012-2013 Xilinx, Michal Simek + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <i2c.h> +#include <asm/errno.h> +#include <asm/arch/hardware.h> + +/* i2c register set */ +struct zynq_i2c_registers { + u32 control; + u32 status; + u32 address; + u32 data; + u32 interrupt_status; + u32 transfer_size; + u32 slave_mon_pause; + u32 time_out; + u32 interrupt_mask; + u32 interrupt_enable; + u32 interrupt_disable; +}; + +/* Control register fields */ +#define ZYNQ_I2C_CONTROL_RW 0x00000001 +#define ZYNQ_I2C_CONTROL_MS 0x00000002 +#define ZYNQ_I2C_CONTROL_NEA 0x00000004 +#define ZYNQ_I2C_CONTROL_ACKEN 0x00000008 +#define ZYNQ_I2C_CONTROL_HOLD 0x00000010 +#define ZYNQ_I2C_CONTROL_SLVMON 0x00000020 +#define ZYNQ_I2C_CONTROL_CLR_FIFO 0x00000040 +#define ZYNQ_I2C_CONTROL_DIV_B_SHIFT 8 +#define ZYNQ_I2C_CONTROL_DIV_B_MASK 0x00003F00 +#define ZYNQ_I2C_CONTROL_DIV_A_SHIFT 14 +#define ZYNQ_I2C_CONTROL_DIV_A_MASK 0x0000C000 + +/* Status register values */ +#define ZYNQ_I2C_STATUS_RXDV 0x00000020 +#define ZYNQ_I2C_STATUS_TXDV 0x00000040 +#define ZYNQ_I2C_STATUS_RXOVF 0x00000080 +#define ZYNQ_I2C_STATUS_BA 0x00000100 + +/* Interrupt register fields */ +#define ZYNQ_I2C_INTERRUPT_COMP 0x00000001 +#define ZYNQ_I2C_INTERRUPT_DATA 0x00000002 +#define ZYNQ_I2C_INTERRUPT_NACK 0x00000004 +#define ZYNQ_I2C_INTERRUPT_TO 0x00000008 +#define ZYNQ_I2C_INTERRUPT_SLVRDY 0x00000010 +#define ZYNQ_I2C_INTERRUPT_RXOVF 0x00000020 +#define ZYNQ_I2C_INTERRUPT_TXOVF 0x00000040 +#define ZYNQ_I2C_INTERRUPT_RXUNF 0x00000080 +#define ZYNQ_I2C_INTERRUPT_ARBLOST 0x00000200 + +#define ZYNQ_I2C_FIFO_DEPTH 16 +#define ZYNQ_I2C_TRANSFERT_SIZE_MAX 255 /* Controller transfer limit */ + +#if defined(CONFIG_ZYNQ_I2C0) +# define ZYNQ_I2C_BASE ZYNQ_I2C_BASEADDR0 +#else +# define ZYNQ_I2C_BASE ZYNQ_I2C_BASEADDR1 +#endif + +static struct zynq_i2c_registers *zynq_i2c = + (struct zynq_i2c_registers *)ZYNQ_I2C_BASE; + +/* I2C init called by cmd_i2c when doing 'i2c reset'. */ +void i2c_init(int requested_speed, int slaveadd) +{ + /* 111MHz / ( (3 * 17) * 22 ) = ~100KHz */ + writel((16 << ZYNQ_I2C_CONTROL_DIV_B_SHIFT) | + (2 << ZYNQ_I2C_CONTROL_DIV_A_SHIFT), &zynq_i2c->control); + + /* Enable master mode, ack, and 7-bit addressing */ + setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_MS | + ZYNQ_I2C_CONTROL_ACKEN | ZYNQ_I2C_CONTROL_NEA); +} + +#ifdef DEBUG +static void zynq_i2c_debug_status(void) +{ + int int_status; + int status; + int_status = readl(&zynq_i2c->interrupt_status); + + status = readl(&zynq_i2c->status); + if (int_status || status) { + debug("Status: "); + if (int_status & ZYNQ_I2C_INTERRUPT_COMP) + debug("COMP "); + if (int_status & ZYNQ_I2C_INTERRUPT_DATA) + debug("DATA "); + if (int_status & ZYNQ_I2C_INTERRUPT_NACK) + debug("NACK "); + if (int_status & ZYNQ_I2C_INTERRUPT_TO) + debug("TO "); + if (int_status & ZYNQ_I2C_INTERRUPT_SLVRDY) + debug("SLVRDY "); + if (int_status & ZYNQ_I2C_INTERRUPT_RXOVF) + debug("RXOVF "); + if (int_status & ZYNQ_I2C_INTERRUPT_TXOVF) + debug("TXOVF "); + if (int_status & ZYNQ_I2C_INTERRUPT_RXUNF) + debug("RXUNF "); + if (int_status & ZYNQ_I2C_INTERRUPT_ARBLOST) + debug("ARBLOST "); + if (status & ZYNQ_I2C_STATUS_RXDV) + debug("RXDV "); + if (status & ZYNQ_I2C_STATUS_TXDV) + debug("TXDV "); + if (status & ZYNQ_I2C_STATUS_RXOVF) + debug("RXOVF "); + if (status & ZYNQ_I2C_STATUS_BA) + debug("BA "); + debug("TS%d ", readl(&zynq_i2c->transfer_size)); + debug("\n"); + } +} +#endif + +/* Wait for an interrupt */ +static u32 zynq_i2c_wait(u32 mask) +{ + int timeout, int_status; + + for (timeout = 0; timeout < 100; timeout++) { + udelay(100); + int_status = readl(&zynq_i2c->interrupt_status); + if (int_status & mask) + break; + } +#ifdef DEBUG + zynq_i2c_debug_status(); +#endif + /* Clear interrupt status flags */ + writel(int_status & mask, &zynq_i2c->interrupt_status); + + return int_status & mask; +} + +/* + * I2C probe called by cmd_i2c when doing 'i2c probe'. + * Begin read, nak data byte, end. + */ +int i2c_probe(u8 dev) +{ + /* Attempt to read a byte */ + setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO | + ZYNQ_I2C_CONTROL_RW); + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); + writel(0xFF, &zynq_i2c->interrupt_status); + writel(dev, &zynq_i2c->address); + writel(1, &zynq_i2c->transfer_size); + + return (zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP | + ZYNQ_I2C_INTERRUPT_NACK) & + ZYNQ_I2C_INTERRUPT_COMP) ? 0 : -ETIMEDOUT; +} + +/* + * I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c + * Begin write, send address byte(s), begin read, receive data bytes, end. + */ +int i2c_read(u8 dev, uint addr, int alen, u8 *data, int length) +{ + u32 status; + u32 i = 0; + u8 *cur_data = data; + + /* Check the hardware can handle the requested bytes */ + if ((length < 0) || (length > ZYNQ_I2C_TRANSFERT_SIZE_MAX)) + return -EINVAL; + + /* Write the register address */ + setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO | + ZYNQ_I2C_CONTROL_HOLD); + /* + * Temporarily disable restart (by clearing hold) + * It doesn't seem to work. + */ + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW | + ZYNQ_I2C_CONTROL_HOLD); + writel(0xFF, &zynq_i2c->interrupt_status); + while (alen--) + writel(addr >> (8*alen), &zynq_i2c->data); + writel(dev, &zynq_i2c->address); + + /* Wait for the address to be sent */ + if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) { + /* Release the bus */ + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); + return -ETIMEDOUT; + } + debug("Device acked address\n"); + + setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO | + ZYNQ_I2C_CONTROL_RW); + /* Start reading data */ + writel(dev, &zynq_i2c->address); + writel(length, &zynq_i2c->transfer_size); + + /* Wait for data */ + do { + status = zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP | + ZYNQ_I2C_INTERRUPT_DATA); + if (!status) { + /* Release the bus */ + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); + return -ETIMEDOUT; + } + debug("Read %d bytes\n", + length - readl(&zynq_i2c->transfer_size)); + for (; i < length - readl(&zynq_i2c->transfer_size); i++) + *(cur_data++) = readl(&zynq_i2c->data); + } while (readl(&zynq_i2c->transfer_size) != 0); + /* All done... release the bus */ + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); + +#ifdef DEBUG + zynq_i2c_debug_status(); +#endif + return 0; +} + +/* + * I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c + * Begin write, send address byte(s), send data bytes, end. + */ +int i2c_write(u8 dev, uint addr, int alen, u8 *data, int length) +{ + u8 *cur_data = data; + + /* Write the register address */ + setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO | + ZYNQ_I2C_CONTROL_HOLD); + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW); + writel(0xFF, &zynq_i2c->interrupt_status); + while (alen--) + writel(addr >> (8*alen), &zynq_i2c->data); + /* Start the tranfer */ + writel(dev, &zynq_i2c->address); + if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) { + /* Release the bus */ + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); + return -ETIMEDOUT; + } + + debug("Device acked address\n"); + while (length--) { + writel(*(cur_data++), &zynq_i2c->data); + if (readl(&zynq_i2c->transfer_size) == ZYNQ_I2C_FIFO_DEPTH) { + if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) { + /* Release the bus */ + clrbits_le32(&zynq_i2c->control, + ZYNQ_I2C_CONTROL_HOLD); + return -ETIMEDOUT; + } + } + } + + /* All done... release the bus */ + clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); + /* Wait for the address and data to be sent */ + if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) + return -ETIMEDOUT; + return 0; +} + +int i2c_set_bus_num(unsigned int bus) +{ + /* Only support bus 0 */ + if (bus > 0) + return -1; + return 0; +} + +unsigned int i2c_get_bus_num(void) +{ + /* Only support bus 0 */ + return 0; +} diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 1d6faa2..7cd4281 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -49,6 +49,7 @@ COBJS-$(CONFIG_SH_MMCIF) += sh_mmcif.o COBJS-$(CONFIG_TEGRA_MMC) += tegra_mmc.o COBJS-$(CONFIG_DWMMC) += dw_mmc.o COBJS-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o +COBJS-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c new file mode 100644 index 0000000..9e37af4 --- /dev/null +++ b/drivers/mmc/zynq_sdhci.c @@ -0,0 +1,40 @@ +/* + * (C) Copyright 2013 Inc. + * + * Xilinx Zynq SD Host Controller Interface + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <common.h> +#include <malloc.h> +#include <sdhci.h> +#include <asm/arch/sys_proto.h> + +int zynq_sdhci_init(u32 regbase) +{ + struct sdhci_host *host = NULL; + + host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); + if (!host) { + printf("zynq_sdhci_init: sdhci_host malloc fail\n"); + return 1; + } + + host->name = "zynq_sdhci"; + host->ioaddr = (void *)regbase; + host->quirks = SDHCI_QUIRK_NO_CD | SDHCI_QUIRK_WAIT_SEND_CMD; + host->version = sdhci_readw(host, SDHCI_HOST_VERSION); + + host->host_caps = MMC_MODE_HC; + + add_sdhci(host, 52000000, 52000000 >> 9); + return 0; +} diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 4b27198..46801c7 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -465,6 +465,16 @@ static struct phy_driver M88E1149S_driver = { .shutdown = &genphy_shutdown, }; +static struct phy_driver M88E1518_driver = { + .name = "Marvell 88E1518", + .uid = 0x1410dd1, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1111s_config, + .startup = &m88e1011s_startup, + .shutdown = &genphy_shutdown, +}; + int phy_marvell_init(void) { phy_register(&M88E1149S_driver); @@ -474,6 +484,7 @@ int phy_marvell_init(void) phy_register(&M88E1118R_driver); phy_register(&M88E1111S_driver); phy_register(&M88E1011S_driver); + phy_register(&M88E1518_driver); return 0; } diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 3596065..eac9b6f 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -33,6 +33,8 @@ #include <phy.h> #include <miiphy.h> #include <watchdog.h> +#include <asm/arch/hardware.h> +#include <asm/arch/sys_proto.h> #if !defined(CONFIG_PHYLIB) # error XILINX_GEM_ETHERNET requires PHYLIB @@ -67,13 +69,14 @@ #define ZYNQ_GEM_NWCTRL_MDEN_MASK 0x00000010 /* Enable MDIO port */ #define ZYNQ_GEM_NWCTRL_STARTTX_MASK 0x00000200 /* Start tx (tx_go) */ -#define ZYNQ_GEM_NWCFG_SPEED 0x00000001 /* 100 Mbps operation */ -#define ZYNQ_GEM_NWCFG_FDEN 0x00000002 /* Full Duplex mode */ -#define ZYNQ_GEM_NWCFG_FSREM 0x00020000 /* FCS removal */ +#define ZYNQ_GEM_NWCFG_SPEED100 0x000000001 /* 100 Mbps operation */ +#define ZYNQ_GEM_NWCFG_SPEED1000 0x000000400 /* 1Gbps operation */ +#define ZYNQ_GEM_NWCFG_FDEN 0x000000002 /* Full Duplex mode */ +#define ZYNQ_GEM_NWCFG_FSREM 0x000020000 /* FCS removal */ #define ZYNQ_GEM_NWCFG_MDCCLKDIV 0x000080000 /* Div pclk by 32, 80MHz */ +#define ZYNQ_GEM_NWCFG_MDCCLKDIV2 0x0000c0000 /* Div pclk by 48, 120MHz */ -#define ZYNQ_GEM_NWCFG_INIT (ZYNQ_GEM_NWCFG_SPEED | \ - ZYNQ_GEM_NWCFG_FDEN | \ +#define ZYNQ_GEM_NWCFG_INIT (ZYNQ_GEM_NWCFG_FDEN | \ ZYNQ_GEM_NWCFG_FSREM | \ ZYNQ_GEM_NWCFG_MDCCLKDIV) @@ -92,6 +95,17 @@ ZYNQ_GEM_DMACR_TXSIZE | \ ZYNQ_GEM_DMACR_RXBUF) +/* Use MII register 1 (MII status register) to detect PHY */ +#define PHY_DETECT_REG 1 + +/* Mask used to verify certain PHY features (or register contents) + * in the register above: + * 0x1000: 10Mbps full duplex support + * 0x0800: 10Mbps half duplex support + * 0x0008: Auto-negotiation support + */ +#define PHY_DETECT_MASK 0x1808 + /* Device registers */ struct zynq_gem_regs { u32 nwctrl; /* Network Control reg */ @@ -134,6 +148,8 @@ struct zynq_gem_priv { u32 rxbd_current; u32 rx_first_buf; int phyaddr; + u32 emio; + int init; struct phy_device *phydev; struct mii_dev *bus; }; @@ -196,6 +212,44 @@ static u32 phywrite(struct eth_device *dev, u32 phy_addr, u32 regnum, u16 data) ZYNQ_GEM_PHYMNTNC_OP_W_MASK, &data); } +static void phy_detection(struct eth_device *dev) +{ + int i; + u16 phyreg; + struct zynq_gem_priv *priv = dev->priv; + + if (priv->phyaddr != -1) { + phyread(dev, priv->phyaddr, PHY_DETECT_REG, &phyreg); + if ((phyreg != 0xFFFF) && + ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { + /* Found a valid PHY address */ + debug("Default phy address %d is valid\n", + priv->phyaddr); + return; + } else { + debug("PHY address is not setup correctly %d\n", + priv->phyaddr); + priv->phyaddr = -1; + } + } + + debug("detecting phy address\n"); + if (priv->phyaddr == -1) { + /* detect the PHY address */ + for (i = 31; i >= 0; i--) { + phyread(dev, i, PHY_DETECT_REG, &phyreg); + if ((phyreg != 0xFFFF) && + ((phyreg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { + /* Found a valid PHY address */ + priv->phyaddr = i; + debug("Found valid phy address, %d\n", i); + return; + } + } + } + printf("PHY is not detected\n"); +} + static int zynq_gem_setup_mac(struct eth_device *dev) { u32 i, macaddrlow, macaddrhigh; @@ -226,7 +280,7 @@ static int zynq_gem_setup_mac(struct eth_device *dev) static int zynq_gem_init(struct eth_device *dev, bd_t * bis) { - u32 i; + u32 i, rclk, clk = 0; struct phy_device *phydev; const u32 stat_size = (sizeof(struct zynq_gem_regs) - offsetof(struct zynq_gem_regs, stat)) / 4; @@ -239,59 +293,92 @@ static int zynq_gem_init(struct eth_device *dev, bd_t * bis) SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full; - /* Disable all interrupts */ - writel(0xFFFFFFFF, ®s->idr); - - /* Disable the receiver & transmitter */ - writel(0, ®s->nwctrl); - writel(0, ®s->txsr); - writel(0, ®s->rxsr); - writel(0, ®s->phymntnc); - - /* Clear the Hash registers for the mac address pointed by AddressPtr */ - writel(0x0, ®s->hashl); - /* Write bits [63:32] in TOP */ - writel(0x0, ®s->hashh); + if (!priv->init) { + /* Disable all interrupts */ + writel(0xFFFFFFFF, ®s->idr); + + /* Disable the receiver & transmitter */ + writel(0, ®s->nwctrl); + writel(0, ®s->txsr); + writel(0, ®s->rxsr); + writel(0, ®s->phymntnc); + + /* Clear the Hash registers for the mac address + * pointed by AddressPtr + */ + writel(0x0, ®s->hashl); + /* Write bits [63:32] in TOP */ + writel(0x0, ®s->hashh); + + /* Clear all counters */ + for (i = 0; i <= stat_size; i++) + readl(®s->stat[i]); + + /* Setup RxBD space */ + memset(&(priv->rx_bd), 0, sizeof(priv->rx_bd)); + /* Create the RxBD ring */ + memset(&(priv->rxbuffers), 0, sizeof(priv->rxbuffers)); + + for (i = 0; i < RX_BUF; i++) { + priv->rx_bd[i].status = 0xF0000000; + priv->rx_bd[i].addr = + (u32)((char *)&(priv->rxbuffers) + + (i * PKTSIZE_ALIGN)); + } + /* WRAP bit to last BD */ + priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; + /* Write RxBDs to IP */ + writel((u32)&(priv->rx_bd), ®s->rxqbase); - /* Clear all counters */ - for (i = 0; i <= stat_size; i++) - readl(®s->stat[i]); + /* Setup for DMA Configuration register */ + writel(ZYNQ_GEM_DMACR_INIT, ®s->dmacr); - /* Setup RxBD space */ - memset(&(priv->rx_bd), 0, sizeof(priv->rx_bd)); - /* Create the RxBD ring */ - memset(&(priv->rxbuffers), 0, sizeof(priv->rxbuffers)); + /* Setup for Network Control register, MDIO, Rx and Tx enable */ + setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK); - for (i = 0; i < RX_BUF; i++) { - priv->rx_bd[i].status = 0xF0000000; - priv->rx_bd[i].addr = (u32)((char *) &(priv->rxbuffers) + - (i * PKTSIZE_ALIGN)); + priv->init++; } - /* WRAP bit to last BD */ - priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; - /* Write RxBDs to IP */ - writel((u32) &(priv->rx_bd), ®s->rxqbase); - /* MAC Setup */ - /* Setup Network Configuration register */ - writel(ZYNQ_GEM_NWCFG_INIT, ®s->nwcfg); - - /* Setup for DMA Configuration register */ - writel(ZYNQ_GEM_DMACR_INIT, ®s->dmacr); - - /* Setup for Network Control register, MDIO, Rx and Tx enable */ - setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK | - ZYNQ_GEM_NWCTRL_RXEN_MASK | ZYNQ_GEM_NWCTRL_TXEN_MASK); + phy_detection(dev); /* interface - look at tsec */ phydev = phy_connect(priv->bus, priv->phyaddr, dev, 0); - phydev->supported &= supported; + phydev->supported = supported | ADVERTISED_Pause | + ADVERTISED_Asym_Pause; phydev->advertising = phydev->supported; priv->phydev = phydev; phy_config(phydev); phy_startup(phydev); + switch (phydev->speed) { + case SPEED_1000: + writel(ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED1000, + ®s->nwcfg); + rclk = (0 << 4) | (1 << 0); + clk = (1 << 20) | (8 << 8) | (0 << 4) | (1 << 0); + break; + case SPEED_100: + clrsetbits_le32(®s->nwcfg, ZYNQ_GEM_NWCFG_SPEED1000, + ZYNQ_GEM_NWCFG_INIT | ZYNQ_GEM_NWCFG_SPEED100); + rclk = 1 << 0; + clk = (5 << 20) | (8 << 8) | (0 << 4) | (1 << 0); + break; + case SPEED_10: + rclk = 1 << 0; + /* FIXME untested */ + clk = (5 << 20) | (8 << 8) | (0 << 4) | (1 << 0); + break; + } + + /* Change the rclk and clk only not using EMIO interface */ + if (!priv->emio) + zynq_slcr_gem_clk_setup(dev->iobase != + ZYNQ_GEM_BASEADDR0, rclk, clk); + + setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | + ZYNQ_GEM_NWCTRL_TXEN_MASK); + return 0; } @@ -307,11 +394,10 @@ static int zynq_gem_send(struct eth_device *dev, void *ptr, int len) writel((u32)&(priv->tx_bd), ®s->txqbase); /* Setup Tx BD */ - memset((void *) &(priv->tx_bd), 0, sizeof(struct emac_bd)); + memset((void *)&(priv->tx_bd), 0, sizeof(struct emac_bd)); priv->tx_bd.addr = (u32)ptr; - priv->tx_bd.status = len | ZYNQ_GEM_TXBUF_LAST_MASK | - ZYNQ_GEM_TXBUF_WRAP_MASK; + priv->tx_bd.status = len | ZYNQ_GEM_TXBUF_LAST_MASK; /* Start transmit */ setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_STARTTX_MASK); @@ -364,19 +450,17 @@ static int zynq_gem_recv(struct eth_device *dev) if ((++priv->rxbd_current) >= RX_BUF) priv->rxbd_current = 0; - - return frame_len; } - return 0; + return frame_len; } static void zynq_gem_halt(struct eth_device *dev) { struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; - /* Disable the receiver & transmitter */ - writel(0, ®s->nwctrl); + clrsetbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_RXEN_MASK | + ZYNQ_GEM_NWCTRL_TXEN_MASK, 0); } static int zynq_gem_miiphyread(const char *devname, uchar addr, @@ -399,7 +483,7 @@ static int zynq_gem_miiphy_write(const char *devname, uchar addr, return phywrite(dev, addr, reg, val); } -int zynq_gem_initialize(bd_t *bis, int base_addr) +int zynq_gem_initialize(bd_t *bis, int base_addr, int phy_addr, u32 emio) { struct eth_device *dev; struct zynq_gem_priv *priv; @@ -415,11 +499,8 @@ int zynq_gem_initialize(bd_t *bis, int base_addr) } priv = dev->priv; -#ifdef CONFIG_PHY_ADDR - priv->phyaddr = CONFIG_PHY_ADDR; -#else - priv->phyaddr = -1; -#endif + priv->phyaddr = phy_addr; + priv->emio = emio; sprintf(dev->name, "Gem.%x", base_addr); |