From 39cf480484fcce5c04a590ee1c30be0c17b02c34 Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Fri, 9 May 2008 21:57:18 +0200 Subject: Add ATMEL LCD driver This patch adds support for the ATMEL LCDC driver which is used on some AT91 and AVR platforms. Is has been tested with the AT91CAP9ADK, AT91SAM9261EK, AT91SAM9263EK and AT91SAM9RLEK boards. Adaptation for AVR32 should probably be easy. Signed-off-by: Stelian Pop Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- common/lcd.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/lcd.c b/common/lcd.c index 914dc2ef7ca..2178f12d5af 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -50,6 +50,12 @@ #include #endif +#if defined(CONFIG_ATMEL_LCD) +#include +#include +extern nand_info_t nand_info[]; +#endif + #ifdef CONFIG_LCD /************************************************************************/ @@ -474,14 +480,22 @@ ulong lcd_setmem (ulong addr) static void lcd_setfgcolor (int color) { +#ifdef CONFIG_ATMEL_LCD + lcd_color_fg = color; +#else lcd_color_fg = color & 0x0F; +#endif } /*----------------------------------------------------------------------*/ static void lcd_setbgcolor (int color) { +#ifdef CONFIG_ATMEL_LCD + lcd_color_bg = color; +#else lcd_color_bg = color & 0x0F; +#endif } /*----------------------------------------------------------------------*/ @@ -508,7 +522,11 @@ static int lcd_getbgcolor (void) #ifdef CONFIG_LCD_LOGO void bitmap_plot (int x, int y) { +#ifdef CONFIG_ATMEL_LCD + uint *cmap; +#else ushort *cmap; +#endif ushort i, j; uchar *bmap; uchar *fb; @@ -533,6 +551,8 @@ void bitmap_plot (int x, int y) cmap = (ushort *)fbi->palette; #elif defined(CONFIG_MPC823) cmap = (ushort *)&(cp->lcd_cmap[BMP_LOGO_OFFSET*sizeof(ushort)]); +#elif defined(CONFIG_ATMEL_LCD) + cmap = (uint *) (panel_info.mmio + ATMEL_LCDC_LUT(0)); #endif WATCHDOG_RESET(); @@ -540,11 +560,26 @@ void bitmap_plot (int x, int y) /* Set color map */ for (i=0; i<(sizeof(bmp_logo_palette)/(sizeof(ushort))); ++i) { ushort colreg = bmp_logo_palette[i]; +#ifdef CONFIG_ATMEL_LCD + uint lut_entry; +#ifdef CONFIG_ATMEL_LCD_BGR555 + lut_entry = ((colreg & 0x000F) << 11) | + ((colreg & 0x00F0) << 2) | + ((colreg & 0x0F00) >> 7); +#else /* CONFIG_ATMEL_LCD_RGB565 */ + lut_entry = ((colreg & 0x000F) << 1) | + ((colreg & 0x00F0) << 3) | + ((colreg & 0x0F00) << 4); +#endif + *(cmap + BMP_LOGO_OFFSET) = lut_entry; + cmap++; +#else /* !CONFIG_ATMEL_LCD */ #ifdef CFG_INVERT_COLORS *cmap++ = 0xffff - colreg; #else *cmap++ = colreg; #endif +#endif /* CONFIG_ATMEL_LCD */ } WATCHDOG_RESET(); @@ -578,7 +613,9 @@ void bitmap_plot (int x, int y) */ int lcd_display_bitmap(ulong bmp_image, int x, int y) { -#if !defined(CONFIG_MCC200) +#ifdef CONFIG_ATMEL_LCD + uint *cmap; +#elif !defined(CONFIG_MCC200) ushort *cmap; #endif ushort i, j; @@ -633,6 +670,8 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) cmap = (ushort *)fbi->palette; #elif defined(CONFIG_MPC823) cmap = (ushort *)&(cp->lcd_cmap[255*sizeof(ushort)]); +#elif defined(CONFIG_ATMEL_LCD) + cmap = (uint *) (panel_info.mmio + ATMEL_LCDC_LUT(0)); #else # error "Don't know location of color map" #endif @@ -708,6 +747,10 @@ static void *lcd_logo (void) #ifdef CONFIG_LCD_INFO char info[80]; char temp[32]; +#ifdef CONFIG_ATMEL_LCD + int i; + ulong dram_size, nand_size; +#endif #endif /* CONFIG_LCD_INFO */ #ifdef CONFIG_SPLASH_SCREEN @@ -765,6 +808,40 @@ static void *lcd_logo (void) # endif /* CONFIG_LCD_INFO */ #endif /* CONFIG_MPC823 */ +#ifdef CONFIG_ATMEL_LCD +# ifdef CONFIG_LCD_INFO + sprintf (info, "%s", U_BOOT_VERSION); + lcd_drawchars (LCD_INFO_X, LCD_INFO_Y, (uchar *)info, strlen(info)); + + sprintf (info, "(C) 2008 ATMEL Corp"); + lcd_drawchars (LCD_INFO_X, LCD_INFO_Y + VIDEO_FONT_HEIGHT, + (uchar *)info, strlen(info)); + + sprintf (info, "at91support@atmel.com"); + lcd_drawchars (LCD_INFO_X, LCD_INFO_Y + VIDEO_FONT_HEIGHT * 2, + (uchar *)info, strlen(info)); + + sprintf (info, "%s CPU at %s MHz", + AT91_CPU_NAME, + strmhz(temp, AT91_MAIN_CLOCK)); + lcd_drawchars (LCD_INFO_X, LCD_INFO_Y + VIDEO_FONT_HEIGHT * 3, + (uchar *)info, strlen(info)); + + dram_size = 0; + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) + dram_size += gd->bd->bi_dram[i].size; + nand_size = 0; + for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) + nand_size += nand_info[i].size; + sprintf (info, " %ld MB SDRAM, %ld MB NAND", + dram_size >> 20, + nand_size >> 20 ); + lcd_drawchars (LCD_INFO_X, LCD_INFO_Y + VIDEO_FONT_HEIGHT * 4, + (uchar *)info, strlen(info)); +# endif /* CONFIG_LCD_INFO */ +#endif /* CONFIG_ATMEL_LCD */ + + #if defined(CONFIG_LCD_LOGO) && !defined(CONFIG_LCD_INFO_BELOW_LOGO) return ((void *)((ulong)lcd_base + BMP_LOGO_HEIGHT * lcd_line_length)); #else -- cgit v1.2.3 From 54694a91428f6c3280fe1ee0923488a1e7e8dbc4 Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Tue, 13 May 2008 17:31:24 +0200 Subject: Cleanup nand_info[] declaration. The nand_info array is declared as extern in several .c files. Those days, nand.h contains a reference to the array, so there is no need to declare it elsewhere. Signed-off-by: Stelian Pop Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- common/cmd_nand.c | 2 -- common/env_nand.c | 3 --- common/lcd.c | 1 - 3 files changed, 6 deletions(-) (limited to 'common') diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 37eb41b20e6..37198d21e8c 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -37,8 +37,6 @@ int find_dev_and_part(const char *id, struct mtd_device **dev, u8 *part_num, struct part_info **part); #endif -extern nand_info_t nand_info[]; /* info for NAND chips */ - static int nand_dump_oob(nand_info_t *nand, ulong off) { return 0; diff --git a/common/env_nand.c b/common/env_nand.c index 49742f5bfb5..f12674d82d5 100644 --- a/common/env_nand.c +++ b/common/env_nand.c @@ -57,9 +57,6 @@ int nand_legacy_rw (struct nand_chip* nand, int cmd, size_t start, size_t len, size_t * retlen, u_char * buf); -/* info for NAND chips, defined in drivers/mtd/nand/nand.c */ -extern nand_info_t nand_info[]; - /* references to names in env_common.c */ extern uchar default_environment[]; extern int default_environment_size; diff --git a/common/lcd.c b/common/lcd.c index 2178f12d5af..ebf377aa89d 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -53,7 +53,6 @@ #if defined(CONFIG_ATMEL_LCD) #include #include -extern nand_info_t nand_info[]; #endif #ifdef CONFIG_LCD -- cgit v1.2.3 From 5922db6c0948506be91e0de44e7a6863a18a417f Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Tue, 13 May 2008 17:31:24 +0200 Subject: Cleanup nand_info[] declaration. The nand_info array is declared as extern in several .c files. Those days, nand.h contains a reference to the array, so there is no need to declare it elsewhere. Signed-off-by: Stelian Pop Signed-off-by: Scott Wood --- common/cmd_nand.c | 2 -- common/env_nand.c | 3 --- 2 files changed, 5 deletions(-) (limited to 'common') diff --git a/common/cmd_nand.c b/common/cmd_nand.c index 37eb41b20e6..37198d21e8c 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -37,8 +37,6 @@ int find_dev_and_part(const char *id, struct mtd_device **dev, u8 *part_num, struct part_info **part); #endif -extern nand_info_t nand_info[]; /* info for NAND chips */ - static int nand_dump_oob(nand_info_t *nand, ulong off) { return 0; diff --git a/common/env_nand.c b/common/env_nand.c index 70d05ad15a2..3a98d2b944b 100644 --- a/common/env_nand.c +++ b/common/env_nand.c @@ -57,9 +57,6 @@ int nand_legacy_rw (struct nand_chip* nand, int cmd, size_t start, size_t len, size_t * retlen, u_char * buf); -/* info for NAND chips, defined in drivers/mtd/nand/nand.c */ -extern nand_info_t nand_info[]; - /* references to names in env_common.c */ extern uchar default_environment[]; extern int default_environment_size; -- cgit v1.2.3 From 95d449ad4de79dd32b1705b8a4d3550f1e9081e3 Mon Sep 17 00:00:00 2001 From: Marian Balakowicz Date: Tue, 13 May 2008 15:53:29 +0200 Subject: Avoid initrd and logbuffer area overlaps Add logbuffer to reserved LMB areas to prevent initrd allocation from overlaping with it. Make sure to use correct logbuffer base address. Signed-off-by: Marian Balakowicz --- common/cmd_log.c | 8 +++++++- common/image.c | 10 ++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/cmd_log.c b/common/cmd_log.c index c6e72ac3c0c..fdcc57571aa 100644 --- a/common/cmd_log.c +++ b/common/cmd_log.c @@ -66,6 +66,12 @@ static logbuff_t *log; #endif static char *lbuf; +unsigned long __logbuffer_base(void) +{ + return CFG_SDRAM_BASE + gd->bd->bi_memsize - LOGBUFF_LEN; +} +unsigned long logbuffer_base (void) __attribute__((weak, alias("__logbuffer_base"))); + void logbuff_init_ptrs (void) { unsigned long tag, post_word; @@ -75,7 +81,7 @@ void logbuff_init_ptrs (void) log = (logbuff_t *)CONFIG_ALT_LH_ADDR; lbuf = (char *)CONFIG_ALT_LB_ADDR; #else - log = (logbuff_t *)(gd->bd->bi_memsize-LOGBUFF_LEN) - 1; + log = (logbuff_t *)(logbuffer_base ()) - 1; lbuf = (char *)log->buf; #endif diff --git a/common/image.c b/common/image.c index 67e594df693..9188024802d 100644 --- a/common/image.c +++ b/common/image.c @@ -35,6 +35,10 @@ #include #endif +#ifdef CONFIG_LOGBUFFER +#include +#endif + #if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) #include #endif @@ -1013,6 +1017,12 @@ int boot_ramdisk_high (struct lmb *lmb, ulong rd_data, ulong rd_len, initrd_high = ~0; } + +#ifdef CONFIG_LOGBUFFER + /* Prevent initrd from overwriting logbuffer */ + lmb_reserve(lmb, logbuffer_base() - LOGBUFF_OVERHEAD, LOGBUFF_RESERVE); +#endif + debug ("## initrd_high = 0x%08lx, copy_to_ram = %d\n", initrd_high, initrd_copy_to_ram); -- cgit v1.2.3 From 81673e9ae14b771cd13faf19947192599cae3959 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Tue, 13 May 2008 19:01:54 -0500 Subject: Make sure common.h is the first include. If common.h isn't first we can get CONFIG_ options defined in the board config file ignored. This can cause an issue if any of those config options impact the size of types of data structures (eg CONFIG_PHYS_64BIT). Signed-off-by: Kumar Gala --- common/dlmalloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/dlmalloc.c b/common/dlmalloc.c index 20c206913c6..c51351e9618 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -1,3 +1,5 @@ +#include + #if 0 /* Moved to malloc.h */ /* ---------- To make a malloc.h, start cutting here ------------ */ @@ -947,7 +949,6 @@ void malloc_stats(); #endif /* 0 */ #endif /* 0 */ /* Moved to malloc.h */ -#include DECLARE_GLOBAL_DATA_PTR; -- cgit v1.2.3 From 110e006fe67fb4a6e1719ae6956c79b7ffc0148b Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Fri, 16 May 2008 11:08:11 +0200 Subject: soft_i2c: Pull SDA high before reading Spotted by Dean Capindale. Systems that support open-drain GPIO properly are allowed provide an empty I2C_TRISTATE define. However, this means that we need to be careful not to drive SDA low when the slave is expected to respond. This patch adds a missing I2C_SDA(1) to read_byte() required to tristate the SDA line on systems that support open-drain GPIO. Signed-off-by: Haavard Skinnemoen --- common/soft_i2c.c | 1 + 1 file changed, 1 insertion(+) (limited to 'common') diff --git a/common/soft_i2c.c b/common/soft_i2c.c index c5d7e205e54..5ef7f303b84 100644 --- a/common/soft_i2c.c +++ b/common/soft_i2c.c @@ -252,6 +252,7 @@ static uchar read_byte(int ack) * Read 8 bits, MSB first. */ I2C_TRISTATE; + I2C_SDA(1); data = 0; for(j = 0; j < 8; j++) { I2C_SCL(0); -- cgit v1.2.3 From d255bb0e78d1cac5b7c8c98cb77a095f5f16de0d Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Fri, 16 May 2008 11:10:31 +0200 Subject: SPI API improvements This patch gets rid of the spi_chipsel table and adds a handful of new functions that makes the SPI layer cleaner and more flexible. Instead of the spi_chipsel table, each board that wants to use SPI gets to implement three hooks: * spi_cs_activate(): Activates the chipselect for a given slave * spi_cs_deactivate(): Deactivates the chipselect for a given slave * spi_cs_is_valid(): Determines if the given bus/chipselect combination can be activated. Not all drivers may need those extra functions however. If that's the case, the board code may just leave them out (assuming they know what the driver needs) or rely on the linker to strip them out (assuming --gc-sections is being used.) To set up communication parameters for a given slave, the driver needs to call spi_setup_slave(). This returns a pointer to an opaque spi_slave struct which must be passed as a parameter to subsequent SPI calls. This struct can be freed by calling spi_free_slave(), but most driver probably don't want to do this. Before starting one or more SPI transfers, the driver must call spi_claim_bus() to gain exclusive access to the SPI bus and initialize the hardware. When all transfers are done, the driver must call spi_release_bus() to make the bus available to others, and possibly shut down the SPI controller hardware. spi_xfer() behaves mostly the same as before, but it now takes a spi_slave parameter instead of a spi_chipsel function pointer. It also got a new parameter, flags, which is used to specify chip select behaviour. This may be extended with other flags in the future. This patch has been build-tested on all powerpc and arm boards involved. I have not tested NIOS since I don't have a toolchain for it installed, so I expect some breakage there even though I've tried fixing up everything I could find by visual inspection. I have run-time tested this on AVR32 ATNGW100 using the atmel_spi and DataFlash drivers posted as a follow-up. I'd like some help testing other boards that use the existing SPI API. But most of all, I'd like some comments on the new API. Is this stuff usable for everyone? If not, why? Changed in v4: - Build fixes for various boards, drivers and commands - Provide common struct spi_slave definition that can be extended by drivers - Pass a struct spi_slave * to spi_cs_activate and spi_cs_deactivate - Make default bus and mode build-time configurable - Override default SPI bus ID and mode on mx32ads and imx31_litekit. Changed in v3: - Add opaque struct spi_slave for controller-specific data associated with a slave. - Add spi_claim_bus() and spi_release_bus() - Add spi_free_slave() - spi_setup() is now called spi_setup_slave() and returns a struct spi_slave - soft_spi now supports four SPI modes (CPOL|CPHA) - Add bus parameter to spi_setup_slave() - Convert the new i.MX32 SPI driver - Convert the new MC13783 RTC driver Changed in v2: - Convert the mpc8xxx_spi driver and the mpc8349emds board to the new API. Signed-off-by: Haavard Skinnemoen Tested-by: Guennadi Liakhovetski --- common/cmd_df.c | 37 ++++++++++++++++ common/cmd_spi.c | 42 ++++++++++-------- common/soft_spi.c | 124 ++++++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 155 insertions(+), 48 deletions(-) create mode 100644 common/cmd_df.c (limited to 'common') diff --git a/common/cmd_df.c b/common/cmd_df.c new file mode 100644 index 00000000000..5f650442c01 --- /dev/null +++ b/common/cmd_df.c @@ -0,0 +1,37 @@ +/* + * Command for accessing DataFlash. + * + * Copyright (C) 2008 Atmel Corporation + */ +#include +#include + +static int do_df(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + const char *cmd; + + /* need at least two arguments */ + if (argc < 2) + goto usage; + + cmd = argv[1]; + + if (strcmp(cmd, "init") == 0) { + df_init(0, 0, 1000000); + return 0; + } + + if (strcmp(cmd, "info") == 0) { + df_show_info(); + return 0; + } + +usage: + printf("Usage:\n%s\n", cmdtp->usage); + return 1; +} + +U_BOOT_CMD( + sf, 2, 1, do_serial_flash, + "sf - Serial flash sub-system\n", + "probe [bus:]cs - init flash device on given SPI bus and CS\n") diff --git a/common/cmd_spi.c b/common/cmd_spi.c index 76044221416..40ee7e7dd3c 100644 --- a/common/cmd_spi.c +++ b/common/cmd_spi.c @@ -37,20 +37,20 @@ # define MAX_SPI_BYTES 32 /* Maximum number of bytes we can handle */ #endif -/* - * External table of chip select functions (see the appropriate board - * support for the actual definition of the table). - */ -extern spi_chipsel_type spi_chipsel[]; -extern int spi_chipsel_cnt; +#ifndef CONFIG_DEFAULT_SPI_BUS +# define CONFIG_DEFAULT_SPI_BUS 0 +#endif +#ifndef CONFIG_DEFAULT_SPI_MODE +# define CONFIG_DEFAULT_SPI_MODE SPI_MODE_0 +#endif /* * Values from last command. */ -static int device; -static int bitlen; -static uchar dout[MAX_SPI_BYTES]; -static uchar din[MAX_SPI_BYTES]; +static unsigned int device; +static int bitlen; +static uchar dout[MAX_SPI_BYTES]; +static uchar din[MAX_SPI_BYTES]; /* * SPI read/write @@ -65,6 +65,7 @@ static uchar din[MAX_SPI_BYTES]; int do_spi (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { + struct spi_slave *slave; char *cp = 0; uchar tmp; int j; @@ -101,19 +102,24 @@ int do_spi (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) } } - if ((device < 0) || (device >= spi_chipsel_cnt)) { - printf("Invalid device %d, giving up.\n", device); - return 1; - } if ((bitlen < 0) || (bitlen > (MAX_SPI_BYTES * 8))) { printf("Invalid bitlen %d, giving up.\n", bitlen); return 1; } - debug ("spi_chipsel[%d] = %08X\n", - device, (uint)spi_chipsel[device]); + /* FIXME: Make these parameters run-time configurable */ + slave = spi_setup_slave(CONFIG_DEFAULT_SPI_BUS, device, 1000000, + CONFIG_DEFAULT_SPI_MODE); + if (!slave) { + printf("Invalid device %d, giving up.\n", device); + return 1; + } + + debug ("spi chipsel = %08X\n", device); - if(spi_xfer(spi_chipsel[device], bitlen, dout, din) != 0) { + spi_claim_bus(slave); + if(spi_xfer(slave, bitlen, dout, din, + SPI_XFER_BEGIN | SPI_XFER_END) != 0) { printf("Error with the SPI transaction.\n"); rcode = 1; } else { @@ -123,6 +129,8 @@ int do_spi (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) } printf("\n"); } + spi_release_bus(slave); + spi_free_slave(slave); return rcode; } diff --git a/common/soft_spi.c b/common/soft_spi.c index e4250616c28..c13165030db 100644 --- a/common/soft_spi.c +++ b/common/soft_spi.c @@ -29,6 +29,8 @@ #if defined(CONFIG_SOFT_SPI) +#include + /*----------------------------------------------------------------------- * Definitions */ @@ -39,6 +41,15 @@ #define PRINTD(fmt,args...) #endif +struct soft_spi_slave { + struct spi_slave slave; + unsigned int mode; +}; + +static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave) +{ + return container_of(slave, struct soft_spi_slave, slave); +} /*=====================================================================*/ /* Public Functions */ @@ -56,6 +67,57 @@ void spi_init (void) #endif } +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct soft_spi_slave *ss; + + if (!spi_cs_is_valid(bus, cs)) + return NULL; + + ss = malloc(sizeof(struct soft_spi_slave)); + if (!ss) + return NULL; + + ss->slave.bus = bus; + ss->slave.cs = cs; + ss->mode = mode; + + /* TODO: Use max_hz to limit the SCK rate */ + + return &ss->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct soft_spi_slave *ss = to_soft_spi(slave); + + free(ss); +} + +int spi_claim_bus(struct spi_slave *slave) +{ +#ifdef CFG_IMMR + volatile immap_t *immr = (immap_t *)CFG_IMMR; +#endif + struct soft_spi_slave *ss = to_soft_spi(slave); + + /* + * Make sure the SPI clock is in idle state as defined for + * this slave. + */ + if (ss->mode & SPI_CPOL) + SPI_SCL(1); + else + SPI_SCL(0); + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* Nothing to do */ +} /*----------------------------------------------------------------------- * SPI transfer @@ -68,50 +130,54 @@ void spi_init (void) * and "din" can point to the same memory location, in which case the * input data overwrites the output data (since both are buffered by * temporary variables, this is OK). - * - * If the chipsel() function is not NULL, it is called with a parameter - * of '1' (chip select active) at the start of the transfer and again with - * a parameter of '0' at the end of the transfer. - * - * If the chipsel() function _is_ NULL, it the responsibility of the - * caller to make the appropriate chip select active before calling - * spi_xfer() and making it inactive after spi_xfer() returns. */ -int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) { #ifdef CFG_IMMR volatile immap_t *immr = (immap_t *)CFG_IMMR; #endif - uchar tmpdin = 0; - uchar tmpdout = 0; - int j; + struct soft_spi_slave *ss = to_soft_spi(slave); + uchar tmpdin = 0; + uchar tmpdout = 0; + const u8 *txd = dout; + u8 *rxd = din; + int cpol = ss->mode & SPI_CPOL; + int cpha = ss->mode & SPI_CPHA; + unsigned int j; - PRINTD("spi_xfer: chipsel %08X dout %08X din %08X bitlen %d\n", - (int)chipsel, *(uint *)dout, *(uint *)din, bitlen); + PRINTD("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n", + slave->bus, slave->cs, *(uint *)txd, *(uint *)rxd, bitlen); - if(chipsel != NULL) { - (*chipsel)(1); /* select the target chip */ - } + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); for(j = 0; j < bitlen; j++) { /* * Check if it is time to work on a new byte. */ if((j % 8) == 0) { - tmpdout = *dout++; + tmpdout = *txd++; if(j != 0) { - *din++ = tmpdin; + *rxd++ = tmpdin; } tmpdin = 0; } - SPI_SCL(0); + + if (!cpha) + SPI_SCL(!cpol); SPI_SDA(tmpdout & 0x80); SPI_DELAY; - SPI_SCL(1); + if (cpha) + SPI_SCL(!cpol); + else + SPI_SCL(cpol); + tmpdin <<= 1; + tmpdin |= SPI_READ; + tmpdout <<= 1; SPI_DELAY; - tmpdin <<= 1; - tmpdin |= SPI_READ; - tmpdout <<= 1; + if (cpha) + SPI_SCL(cpol); } /* * If the number of bits isn't a multiple of 8, shift the last @@ -120,14 +186,10 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din) */ if((bitlen % 8) != 0) tmpdin <<= 8 - (bitlen % 8); - *din++ = tmpdin; - - SPI_SCL(0); /* SPI wants the clock left low for idle */ + *rxd++ = tmpdin; - if(chipsel != NULL) { - (*chipsel)(0); /* deselect the target chip */ - - } + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); return(0); } -- cgit v1.2.3 From b6368467e6a97f225e0a5fd7bfc5c7598ef5ddc4 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Fri, 16 May 2008 11:10:34 +0200 Subject: SPI Flash: Add "sf" command This adds a new command, "sf" which can be used to manipulate SPI flash. Currently, initialization, reading, writing and erasing is supported. Signed-off-by: Haavard Skinnemoen --- common/Makefile | 1 + common/cmd_sf.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 common/cmd_sf.c (limited to 'common') diff --git a/common/Makefile b/common/Makefile index 96787992272..d90b5f26b88 100644 --- a/common/Makefile +++ b/common/Makefile @@ -143,6 +143,7 @@ COBJS-y += xyzModem.o COBJS-y += cmd_mac.o COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o COBJS-$(CONFIG_MP) += cmd_mp.o +COBJS-$(CONFIG_CMD_SF) += cmd_sf.o COBJS := $(COBJS-y) SRCS := $(AOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/common/cmd_sf.c b/common/cmd_sf.c new file mode 100644 index 00000000000..8c0a7514dfa --- /dev/null +++ b/common/cmd_sf.c @@ -0,0 +1,191 @@ +/* + * Command for accessing SPI flash. + * + * Copyright (C) 2008 Atmel Corporation + */ +#include +#include + +#include + +#ifndef CONFIG_SF_DEFAULT_SPEED +# define CONFIG_SF_DEFAULT_SPEED 1000000 +#endif +#ifndef CONFIG_SF_DEFAULT_MODE +# define CONFIG_SF_DEFAULT_MODE SPI_MODE_3 +#endif + +static struct spi_flash *flash; + +static int do_spi_flash_probe(int argc, char *argv[]) +{ + unsigned int bus = 0; + unsigned int cs; + unsigned int speed = CONFIG_SF_DEFAULT_SPEED; + unsigned int mode = CONFIG_SF_DEFAULT_MODE; + char *endp; + struct spi_flash *new; + + if (argc < 2) + goto usage; + + cs = simple_strtoul(argv[1], &endp, 0); + if (*argv[1] == 0 || (*endp != 0 && *endp != ':')) + goto usage; + if (*endp == ':') { + if (endp[1] == 0) + goto usage; + + bus = cs; + cs = simple_strtoul(endp + 1, &endp, 0); + if (*endp != 0) + goto usage; + } + + if (argc >= 3) { + speed = simple_strtoul(argv[2], &endp, 0); + if (*argv[2] == 0 || *endp != 0) + goto usage; + } + if (argc >= 4) { + mode = simple_strtoul(argv[3], &endp, 0); + if (*argv[3] == 0 || *endp != 0) + goto usage; + } + + new = spi_flash_probe(bus, cs, speed, mode); + if (!new) { + printf("Failed to initialize SPI flash at %u:%u\n", bus, cs); + return 1; + } + + if (flash) + spi_flash_free(flash); + flash = new; + + printf("%u KiB %s at %u:%u is now current device\n", + flash->size >> 10, flash->name, bus, cs); + + return 0; + +usage: + puts("Usage: sf probe [bus:]cs [hz] [mode]\n"); + return 1; +} + +static int do_spi_flash_read_write(int argc, char *argv[]) +{ + unsigned long addr; + unsigned long offset; + unsigned long len; + void *buf; + char *endp; + int ret; + + if (argc < 4) + goto usage; + + addr = simple_strtoul(argv[1], &endp, 16); + if (*argv[1] == 0 || *endp != 0) + goto usage; + offset = simple_strtoul(argv[2], &endp, 16); + if (*argv[2] == 0 || *endp != 0) + goto usage; + len = simple_strtoul(argv[3], &endp, 16); + if (*argv[3] == 0 || *endp != 0) + goto usage; + + buf = map_physmem(addr, len, MAP_WRBACK); + if (!buf) { + puts("Failed to map physical memory\n"); + return 1; + } + + if (strcmp(argv[0], "read") == 0) + ret = spi_flash_read(flash, offset, len, buf); + else + ret = spi_flash_write(flash, offset, len, buf); + + unmap_physmem(buf, len); + + if (ret) { + printf("SPI flash %s failed\n", argv[0]); + return 1; + } + + return 0; + +usage: + printf("Usage: sf %s addr offset len\n", argv[0]); + return 1; +} + +static int do_spi_flash_erase(int argc, char *argv[]) +{ + unsigned long offset; + unsigned long len; + char *endp; + int ret; + + if (argc < 3) + goto usage; + + offset = simple_strtoul(argv[1], &endp, 16); + if (*argv[1] == 0 || *endp != 0) + goto usage; + len = simple_strtoul(argv[2], &endp, 16); + if (*argv[2] == 0 || *endp != 0) + goto usage; + + ret = spi_flash_erase(flash, offset, len); + if (ret) { + printf("SPI flash %s failed\n", argv[0]); + return 1; + } + + return 0; + +usage: + puts("Usage: sf erase offset len\n"); + return 1; +} + +static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + const char *cmd; + + /* need at least two arguments */ + if (argc < 2) + goto usage; + + cmd = argv[1]; + + if (strcmp(cmd, "probe") == 0) + return do_spi_flash_probe(argc - 1, argv + 1); + + /* The remaining commands require a selected device */ + if (!flash) { + puts("No SPI flash selected. Please run `sf probe'\n"); + return 1; + } + + if (strcmp(cmd, "read") == 0 || strcmp(cmd, "write") == 0) + return do_spi_flash_read_write(argc - 1, argv + 1); + if (strcmp(cmd, "erase") == 0) + return do_spi_flash_erase(argc - 1, argv + 1); + +usage: + printf("Usage:\n%s\n", cmdtp->usage); + return 1; +} + +U_BOOT_CMD( + sf, 5, 1, do_spi_flash, + "sf - SPI flash sub-system\n", + "probe [bus:]cs [hz] [mode] - init flash device on given SPI bus\n" + " and chip select\n" + "sf read addr offset len - read `len' bytes starting at\n" + " `offset' to memory at `addr'\n" + "sf write addr offset len - write `len' bytes from memory\n" + " at `addr' to flash at `offset'\n" + "sf erase offset len - erase `len' bytes from `offset'\n"); -- cgit v1.2.3 From 8c66497e06bf803489c589df58ee591d71033274 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Fri, 16 May 2008 11:10:35 +0200 Subject: Add support for environment in SPI flash This is pretty incomplete...it doesn't handle reading the environment before relocation, it doesn't support redundant environment, and it doesn't support embedded environment. But apart from that, it does seem to work. Signed-off-by: Haavard Skinnemoen --- common/Makefile | 1 + common/cmd_nvedit.c | 3 +- common/env_common.c | 3 +- common/env_sf.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 common/env_sf.c (limited to 'common') diff --git a/common/Makefile b/common/Makefile index d90b5f26b88..b425795e928 100644 --- a/common/Makefile +++ b/common/Makefile @@ -113,6 +113,7 @@ COBJS-y += env_dataflash.o COBJS-y += env_flash.o COBJS-y += env_eeprom.o COBJS-y += env_onenand.o +COBJS-y += env_sf.o COBJS-y += env_nvram.o COBJS-y += env_nowhere.o COBJS-y += exports.o diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index 9c5d1fcb905..49f134a92e5 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -58,8 +58,9 @@ DECLARE_GLOBAL_DATA_PTR; !defined(CFG_ENV_IS_IN_DATAFLASH) && \ !defined(CFG_ENV_IS_IN_NAND) && \ !defined(CFG_ENV_IS_IN_ONENAND) && \ + !defined(CFG_ENV_IS_IN_SPI_FLASH) && \ !defined(CFG_ENV_IS_NOWHERE) -# error Define one of CFG_ENV_IS_IN_{NVRAM|EEPROM|FLASH|DATAFLASH|ONENAND|NOWHERE} +# error Define one of CFG_ENV_IS_IN_{NVRAM|EEPROM|FLASH|DATAFLASH|ONENAND|SPI_FLASH|NOWHERE} #endif #define XMK_STR(x) #x diff --git a/common/env_common.c b/common/env_common.c index a49481244e2..e6df9a5883d 100644 --- a/common/env_common.c +++ b/common/env_common.c @@ -134,7 +134,8 @@ uchar default_environment[] = { "\0" }; -#if defined(CFG_ENV_IS_IN_NAND) /* Environment is in Nand Flash */ +#if defined(CFG_ENV_IS_IN_NAND) /* Environment is in Nand Flash */ \ + || defined(CFG_ENV_IS_IN_SPI_FLASH) int default_environment_size = sizeof(default_environment); #endif diff --git a/common/env_sf.c b/common/env_sf.c new file mode 100644 index 00000000000..d641a9a73ca --- /dev/null +++ b/common/env_sf.c @@ -0,0 +1,131 @@ +/* + * (C) Copyright 2000-2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * (C) Copyright 2008 Atmel Corporation + * + * 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 + +#ifdef CFG_ENV_IS_IN_SPI_FLASH + +#include +#include + +#ifndef CFG_ENV_SPI_BUS +# define CFG_ENV_SPI_BUS 0 +#endif +#ifndef CFG_ENV_SPI_CS +# define CFG_ENV_SPI_CS 0 +#endif +#ifndef CFG_ENV_SPI_MAX_HZ +# define CFG_ENV_SPI_MAX_HZ 1000000 +#endif +#ifndef CFG_ENV_SPI_MODE +# define CFG_ENV_SPI_MODE SPI_MODE_3 +#endif + +DECLARE_GLOBAL_DATA_PTR; + +/* references to names in env_common.c */ +extern uchar default_environment[]; +extern int default_environment_size; + +char * env_name_spec = "SPI Flash"; +env_t *env_ptr; + +static struct spi_flash *env_flash; + +uchar env_get_char_spec(int index) +{ + return *((uchar *)(gd->env_addr + index)); +} + +int saveenv(void) +{ + if (!env_flash) { + puts("Environment SPI flash not initialized\n"); + return 1; + } + + puts("Erasing SPI flash..."); + if (spi_flash_erase(env_flash, CFG_ENV_OFFSET, CFG_ENV_SIZE)) + return 1; + + puts("Writing to SPI flash..."); + if (spi_flash_write(env_flash, CFG_ENV_OFFSET, CFG_ENV_SIZE, env_ptr)) + return 1; + + puts("done\n"); + return 0; +} + +void env_relocate_spec(void) +{ + int ret; + + env_flash = spi_flash_probe(CFG_ENV_SPI_BUS, CFG_ENV_SPI_CS, + CFG_ENV_SPI_MAX_HZ, CFG_ENV_SPI_MODE); + if (!env_flash) + goto err_probe; + + ret = spi_flash_read(env_flash, CFG_ENV_OFFSET, CFG_ENV_SIZE, env_ptr); + if (ret) + goto err_read; + + if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc) + goto err_crc; + + gd->env_valid = 1; + + return; + +err_read: + spi_flash_free(env_flash); + env_flash = NULL; +err_probe: +err_crc: + puts("*** Warning - bad CRC, using default environment\n\n"); + + if (default_environment_size > CFG_ENV_SIZE) { + gd->env_valid = 0; + puts("*** Error - default environment is too large\n\n"); + return; + } + + memset(env_ptr, 0, sizeof(env_t)); + memcpy(env_ptr->data, default_environment, default_environment_size); + env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE); + gd->env_valid = 1; +} + +int env_init(void) +{ + /* SPI flash isn't usable before relocation */ + gd->env_addr = (ulong)&default_environment[0]; + gd->env_valid = 1; + + return 0; +} + +#endif /* CFG_ENV_IS_IN_SPI_FLASH */ -- cgit v1.2.3 From 35ef877f0a8f6232cdef748f442fed5accb2b641 Mon Sep 17 00:00:00 2001 From: Peter Tyser Date: Thu, 22 May 2008 18:56:52 -0500 Subject: Additional fix to readline_into_buffer() with CONFIG_CMDLINE_EDITING before relocating Removed unneeded command line history initialization. Also, the original code would access the 'initted' variable before relocation to SDRAM which resulted in erratic behavior since the bss is not initialized when executing from flash. Signed-off-by: Peter Tyser --- common/main.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'common') diff --git a/common/main.c b/common/main.c index a17b60b3aa9..046da6f23ca 100644 --- a/common/main.c +++ b/common/main.c @@ -940,12 +940,6 @@ int readline_into_buffer (const char *const prompt, char * buffer) int rc; static int initted = 0; - if (!initted) { - hist_init(); - initted = 1; - } - - /* * History uses a global array which is not * writable until after relocation to RAM. -- cgit v1.2.3