diff options
Diffstat (limited to 'board/evb64260')
-rw-r--r-- | board/evb64260/i2c.c | 315 | ||||
-rw-r--r-- | board/evb64260/intel_flash.c | 277 |
2 files changed, 592 insertions, 0 deletions
diff --git a/board/evb64260/i2c.c b/board/evb64260/i2c.c new file mode 100644 index 0000000..22cb809 --- /dev/null +++ b/board/evb64260/i2c.c @@ -0,0 +1,315 @@ +#include <common.h> +#include <mpc8xx.h> +#include <malloc.h> +#include <galileo/gt64260R.h> +#include <galileo/core.h> + +#define MAX_I2C_RETRYS 10 +#define I2C_DELAY 1000 /* Should be at least the # of MHz of Tclk */ +#undef DEBUG_I2C + +#ifdef DEBUG_I2C +#define DP(x) x +#else +#define DP(x) +#endif + +/* Assuming that there is only one master on the bus (us) */ + +static void +i2c_init(int speed, int slaveaddr) +{ + unsigned int n, m, freq, margin, power; + unsigned int actualFreq, actualN=0, actualM=0; + unsigned int control, status; + unsigned int minMargin = 0xffffffff; + unsigned int tclk = 125000000; + + DP(puts("i2c_init\n")); + + for(n = 0 ; n < 8 ; n++) + { + for(m = 0 ; m < 16 ; m++) + { + power = 2<<n; /* power = 2^(n+1) */ + freq = tclk/(10*(m+1)*power); + if (speed > freq) + margin = speed - freq; + else + margin = freq - speed; + if(margin < minMargin) + { + minMargin = margin; + actualFreq = freq; + actualN = n; + actualM = m; + } + } + } + + DP(puts("setup i2c bus\n")); + + /* Setup bus */ + + GT_REG_WRITE(I2C_SOFT_RESET, 0); + + DP(puts("udelay...\n")); + + udelay(I2C_DELAY); + + DP(puts("set baudrate\n")); + + GT_REG_WRITE(I2C_STATUS_BAUDE_RATE, (actualM << 3) | actualN); + GT_REG_WRITE(I2C_CONTROL, (0x1 << 2) | (0x1 << 6)); + + udelay(I2C_DELAY * 10); + + DP(puts("read control, baudrate\n")); + + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + GT_REG_READ(I2C_CONTROL, &control); +} + +static uchar +i2c_start(void) +{ + unsigned int control, status; + int count = 0; + + DP(puts("i2c_start\n")); + + /* Set the start bit */ + + GT_REG_READ(I2C_CONTROL, &control); + control |= (0x1 << 5); + GT_REG_WRITE(I2C_CONTROL, control); + + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + + count = 0; + while ((status & 0xff) != 0x08) { + udelay(I2C_DELAY); + if (count > 20) { + GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ + return (status); + } + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count++; + } + + return (0); +} + +static uchar +i2c_select_device(uchar dev_addr, uchar read, int ten_bit) +{ + unsigned int status, data, bits = 7; + int count = 0; + + DP(puts("i2c_select_device\n")); + + /* Output slave address */ + + if (ten_bit) { + bits = 10; + } + + data = (dev_addr << 1); + /* set the read bit */ + data |= read; + GT_REG_WRITE(I2C_DATA, data); + /* assert the address */ + RESET_REG_BITS(I2C_CONTROL, BIT3); + + udelay(I2C_DELAY); + + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count = 0; + while (((status & 0xff) != 0x40) && ((status & 0xff) != 0x18)) { + udelay(I2C_DELAY); + if (count > 20) { + GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ + return(status); + } + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count++; + } + + if (bits == 10) { + printf("10 bit I2C addressing not yet implemented\n"); + return (0xff); + } + + return (0); +} + +static uchar +i2c_get_data(uchar* return_data, int len) { + + unsigned int data, status; + int count = 0; + + DP(puts("i2c_get_data\n")); + + while (len) { + + /* Get and return the data */ + + RESET_REG_BITS(I2C_CONTROL, (0x1 << 3)); + + udelay(I2C_DELAY * 5); + + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count++; + while ((status & 0xff) != 0x50) { + udelay(I2C_DELAY); + if(count > 2) { + GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ + return 0; + } + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count++; + } + GT_REG_READ(I2C_DATA, &data); + len--; + *return_data = (uchar)data; + return_data++; + } + RESET_REG_BITS(I2C_CONTROL, BIT2|BIT3); + while ((status & 0xff) != 0x58) { + udelay(I2C_DELAY); + if(count > 200) { + GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ + return (status); + } + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count++; + } + GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /* stop */ + + return (0); +} + +static uchar +i2c_write_data(unsigned int data, int len) +{ + unsigned int status; + int count = 0; + + DP(puts("i2c_write_data\n")); + + if (len > 4) + return -1; + + while (len) { + /* Set and assert the data */ + + GT_REG_WRITE(I2C_DATA, (unsigned int)data); + RESET_REG_BITS(I2C_CONTROL, (0x1 << 3)); + + udelay(I2C_DELAY); + + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count++; + while ((status & 0xff) != 0x28) { + udelay(I2C_DELAY); + if(count > 20) { + GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ + return (status); + } + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count++; + } + len--; + } + GT_REG_WRITE(I2C_CONTROL, (0x1 << 3) | (0x1 << 4)); + GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); + + udelay(I2C_DELAY * 10); + + return (0); +} + +static uchar +i2c_set_dev_offset(uchar dev_addr, unsigned int offset, int ten_bit) +{ + uchar status; + + DP(puts("i2c_set_dev_offset\n")); + + status = i2c_select_device(dev_addr, 0, ten_bit); + if (status) { +#ifdef DEBUG_I2C + printf("Failed to select device setting offset: 0x%02x\n", + status); +#endif + return status; + } + + status = i2c_write_data(offset, 1); + if (status) { +#ifdef DEBUG_I2C + printf("Failed to write data: 0x%02x\n", status); +#endif + return status; + } + + return (0); +} + +uchar +i2c_read(uchar dev_addr, unsigned int offset, int len, uchar* data, + int ten_bit) +{ + uchar status = 0; + unsigned int i2cFreq = 400000; + + DP(puts("i2c_read\n")); + + i2c_init(i2cFreq,0); + + status = i2c_start(); + + if (status) { +#ifdef DEBUG_I2C + printf("Transaction start failed: 0x%02x\n", status); +#endif + return status; + } + + status = i2c_set_dev_offset(dev_addr, 0, 0); + if (status) { +#ifdef DEBUG_I2C + printf("Failed to set offset: 0x%02x\n", status); +#endif + return status; + } + + i2c_init(i2cFreq,0); + + status = i2c_start(); + if (status) { +#ifdef DEBUG_I2C + printf("Transaction restart failed: 0x%02x\n", status); +#endif + return status; + } + + status = i2c_select_device(dev_addr, 1, ten_bit); + if (status) { +#ifdef DEBUG_I2C + printf("Address not acknowledged: 0x%02x\n", status); +#endif + return status; + } + + status = i2c_get_data(data, len); + if (status) { +#ifdef DEBUG_I2C + printf("Data not recieved: 0x%02x\n", status); +#endif + return status; + } + + return 0; +} diff --git a/board/evb64260/intel_flash.c b/board/evb64260/intel_flash.c new file mode 100644 index 0000000..ed6a2a0 --- /dev/null +++ b/board/evb64260/intel_flash.c @@ -0,0 +1,277 @@ +/* + * (C) Copyright 2000 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * 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 + * + * Hacked for the Hymod board by Murray.Jensen@cmst.csiro.au, 20-Oct-00 + */ + +#include <common.h> +#include <mpc8xx.h> +#include <galileo/gt64260R.h> +#include <galileo/memory.h> +#include "intel_flash.h" + + +/*----------------------------------------------------------------------- + * Protection Flags: + */ +#define FLAG_PROTECT_SET 0x01 +#define FLAG_PROTECT_CLEAR 0x02 + +static void +bank_reset(flash_info_t *info, int sect) +{ + bank_addr_t addrw, eaddrw; + + addrw = (bank_addr_t)info->start[sect]; + eaddrw = BANK_ADDR_NEXT_WORD(addrw); + + while (addrw < eaddrw) { +#ifdef FLASH_DEBUG + printf(" writing reset cmd to addr 0x%08lx\n", + (unsigned long)addrw); +#endif + *addrw = BANK_CMD_RST; + addrw++; + } +} + +static void +bank_erase_init(flash_info_t *info, int sect) +{ + bank_addr_t addrw, saddrw, eaddrw; + int flag; + +#ifdef FLASH_DEBUG + printf("0x%08x BANK_CMD_PROG\n", BANK_CMD_PROG); + printf("0x%08x BANK_CMD_ERASE1\n", BANK_CMD_ERASE1); + printf("0x%08x BANK_CMD_ERASE2\n", BANK_CMD_ERASE2); + printf("0x%08x BANK_CMD_CLR_STAT\n", BANK_CMD_CLR_STAT); + printf("0x%08x BANK_CMD_RST\n", BANK_CMD_RST); + printf("0x%08x BANK_STAT_RDY\n", BANK_STAT_RDY); + printf("0x%08x BANK_STAT_ERR\n", BANK_STAT_ERR); +#endif + + saddrw = (bank_addr_t)info->start[sect]; + eaddrw = BANK_ADDR_NEXT_WORD(saddrw); + +#ifdef FLASH_DEBUG + printf("erasing sector %d, start addr = 0x%08lx " + "(bank next word addr = 0x%08lx)\n", sect, + (unsigned long)saddrw, (unsigned long)eaddrw); +#endif + + /* Disable intrs which might cause a timeout here */ + flag = disable_interrupts(); + + for (addrw = saddrw; addrw < eaddrw; addrw++) { +#ifdef FLASH_DEBUG + printf(" writing erase cmd to addr 0x%08lx\n", + (unsigned long)addrw); +#endif + *addrw = BANK_CMD_ERASE1; + *addrw = BANK_CMD_ERASE2; + } + + /* re-enable interrupts if necessary */ + if (flag) + enable_interrupts(); +} + +static int +bank_erase_poll(flash_info_t *info, int sect) +{ + bank_addr_t addrw, saddrw, eaddrw; + int sectdone, haderr; + + saddrw = (bank_addr_t)info->start[sect]; + eaddrw = BANK_ADDR_NEXT_WORD(saddrw); + + sectdone = 1; + haderr = 0; + + for (addrw = saddrw; addrw < eaddrw; addrw++) { + bank_word_t stat = *addrw; + +#ifdef FLASH_DEBUG + printf(" checking status at addr " + "0x%08x [0x%08x]\n", + (unsigned long)addrw, stat); +#endif + if ((stat & BANK_STAT_RDY) != BANK_STAT_RDY) + sectdone = 0; + else if ((stat & BANK_STAT_ERR) != 0) { + printf(" failed on sector %d " + "(stat = 0x%08x) at " + "address 0x%p\n", + sect, stat, addrw); + *addrw = BANK_CMD_CLR_STAT; + haderr = 1; + } + } + + if (haderr) + return (-1); + else + return (sectdone); +} + +int +write_word_intel(bank_addr_t addr, bank_word_t value) +{ + bank_word_t stat; + ulong start; + int flag, retval; + + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + + *addr = BANK_CMD_PROG; + + *addr = value; + + /* re-enable interrupts if necessary */ + if (flag) + enable_interrupts(); + + retval = 0; + + /* data polling for D7 */ + start = get_timer (0); + do { + if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { + retval = 1; + goto done; + } + stat = *addr; + } while ((stat & BANK_STAT_RDY) != BANK_STAT_RDY); + + if ((stat & BANK_STAT_ERR) != 0) { + printf("flash program failed (stat = 0x%08lx) " + "at address 0x%08lx\n", (ulong)stat, (ulong)addr); + *addr = BANK_CMD_CLR_STAT; + retval = 3; + } + +done: + /* reset to read mode */ + *addr = BANK_CMD_RST; + + return (retval); +} + +/*----------------------------------------------------------------------- + */ + +int +flash_erase_intel(flash_info_t *info, int s_first, int s_last) +{ + int prot, sect, haderr; + ulong start, now, last; + +#ifdef FLASH_DEBUG + printf("\nflash_erase: erase %d sectors (%d to %d incl.) from\n" + " Bank # %d: ", s_last - s_first + 1, s_first, s_last, + (info - flash_info) + 1); + flash_print_info(info); +#endif + + if ((s_first < 0) || (s_first > s_last)) { + if (info->flash_id == FLASH_UNKNOWN) { + printf ("- missing\n"); + } else { + printf ("- no sectors to erase\n"); + } + return 1; + } + + prot = 0; + for (sect=s_first; sect<=s_last; ++sect) { + if (info->protect[sect]) { + prot++; + } + } + + if (prot) { + printf("- Warning: %d protected sector%s will not be erased!\n", + prot, (prot > 1 ? "s" : "")); + } + + start = get_timer (0); + last = 0; + haderr = 0; + + for (sect = s_first; sect <= s_last; sect++) { + if (info->protect[sect] == 0) { /* not protected */ + ulong estart; + int sectdone; + + bank_erase_init(info, sect); + + /* wait at least 80us - let's wait 1 ms */ + udelay (1000); + + estart = get_timer(start); + + do { + now = get_timer(start); + + if (now - estart > CFG_FLASH_ERASE_TOUT) { + printf ("Timeout (sect %d)\n", sect); + haderr = 1; + break; + } + +#ifndef FLASH_DEBUG + /* show that we're waiting */ + if ((now - last) > 1000) { /* every second */ + putc ('.'); + last = now; + } +#endif + + sectdone = bank_erase_poll(info, sect); + + if (sectdone < 0) { + haderr = 1; + break; + } + + } while (!sectdone); + + if (haderr) + break; + } + } + + if (haderr > 0) + printf (" failed\n"); + else + printf (" done\n"); + + /* reset to read mode */ + for (sect = s_first; sect <= s_last; sect++) { + if (info->protect[sect] == 0) { /* not protected */ + bank_reset(info, sect); + } + } + return haderr; +} |