1c2485364SHeiko Schocher /* 2c2485364SHeiko Schocher * (C) Copyright 2008 3c2485364SHeiko Schocher * Heiko Schocher, DENX Software Engineering, hs@denx.de. 4c2485364SHeiko Schocher * 5c2485364SHeiko Schocher * See file CREDITS for list of people who contributed to this 6c2485364SHeiko Schocher * project. 7c2485364SHeiko Schocher * 8c2485364SHeiko Schocher * This program is free software; you can redistribute it and/or 9c2485364SHeiko Schocher * modify it under the terms of the GNU General Public License as 10c2485364SHeiko Schocher * published by the Free Software Foundation; either version 2 of 11c2485364SHeiko Schocher * the License, or (at your option) any later version. 12c2485364SHeiko Schocher * 13c2485364SHeiko Schocher * This program is distributed in the hope that it will be useful, 14c2485364SHeiko Schocher * but WITHOUT ANY WARRANTY; without even the implied warranty of 15c2485364SHeiko Schocher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16c2485364SHeiko Schocher * GNU General Public License for more details. 17c2485364SHeiko Schocher * 18c2485364SHeiko Schocher * You should have received a copy of the GNU General Public License 19c2485364SHeiko Schocher * along with this program; if not, write to the Free Software 20c2485364SHeiko Schocher * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21c2485364SHeiko Schocher * MA 02111-1307 USA 22c2485364SHeiko Schocher */ 23c2485364SHeiko Schocher 24c2485364SHeiko Schocher #include <common.h> 25210c8c00SHeiko Schocher #if defined(CONFIG_MGCOGE) 26c2485364SHeiko Schocher #include <mpc8260.h> 27210c8c00SHeiko Schocher #endif 28c2485364SHeiko Schocher #include <ioports.h> 29c2485364SHeiko Schocher #include <malloc.h> 308f64da7fSHeiko Schocher #include <hush.h> 31210c8c00SHeiko Schocher #include <net.h> 32210c8c00SHeiko Schocher #include <asm/io.h> 33c2485364SHeiko Schocher 34c2485364SHeiko Schocher #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT) 35c2485364SHeiko Schocher #include <libfdt.h> 36c2485364SHeiko Schocher #endif 37c2485364SHeiko Schocher 38c2485364SHeiko Schocher #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) 39c2485364SHeiko Schocher #include <i2c.h> 40c2485364SHeiko Schocher 41c2485364SHeiko Schocher extern int i2c_soft_read_pin (void); 42c2485364SHeiko Schocher 438f64da7fSHeiko Schocher int ivm_calc_crc (unsigned char *buf, int len) 448f64da7fSHeiko Schocher { 458f64da7fSHeiko Schocher const unsigned short crc_tab[16] = { 468f64da7fSHeiko Schocher 0x0000, 0xCC01, 0xD801, 0x1400, 478f64da7fSHeiko Schocher 0xF001, 0x3C00, 0x2800, 0xE401, 488f64da7fSHeiko Schocher 0xA001, 0x6C00, 0x7800, 0xB401, 498f64da7fSHeiko Schocher 0x5000, 0x9C01, 0x8801, 0x4400}; 508f64da7fSHeiko Schocher 518f64da7fSHeiko Schocher unsigned short crc = 0; /* final result */ 528f64da7fSHeiko Schocher unsigned short r1 = 0; /* temp */ 538f64da7fSHeiko Schocher unsigned char byte = 0; /* input buffer */ 548f64da7fSHeiko Schocher int i; 558f64da7fSHeiko Schocher 568f64da7fSHeiko Schocher /* calculate CRC from array data */ 578f64da7fSHeiko Schocher for (i = 0; i < len; i++) { 588f64da7fSHeiko Schocher byte = buf[i]; 598f64da7fSHeiko Schocher 608f64da7fSHeiko Schocher /* lower 4 bits */ 618f64da7fSHeiko Schocher r1 = crc_tab[crc & 0xF]; 628f64da7fSHeiko Schocher crc = ((crc) >> 4) & 0x0FFF; 638f64da7fSHeiko Schocher crc = crc ^ r1 ^ crc_tab[byte & 0xF]; 648f64da7fSHeiko Schocher 658f64da7fSHeiko Schocher /* upper 4 bits */ 668f64da7fSHeiko Schocher r1 = crc_tab[crc & 0xF]; 678f64da7fSHeiko Schocher crc = (crc >> 4) & 0x0FFF; 688f64da7fSHeiko Schocher crc = crc ^ r1 ^ crc_tab[(byte >> 4) & 0xF]; 698f64da7fSHeiko Schocher } 708f64da7fSHeiko Schocher return crc; 718f64da7fSHeiko Schocher } 728f64da7fSHeiko Schocher 738f64da7fSHeiko Schocher static int ivm_set_value (char *name, char *value) 748f64da7fSHeiko Schocher { 758f64da7fSHeiko Schocher char tempbuf[256]; 768f64da7fSHeiko Schocher 778f64da7fSHeiko Schocher if (value != NULL) { 788f64da7fSHeiko Schocher sprintf (tempbuf, "%s=%s", name, value); 798f64da7fSHeiko Schocher return set_local_var (tempbuf, 0); 808f64da7fSHeiko Schocher } else { 818f64da7fSHeiko Schocher unset_local_var (name); 828f64da7fSHeiko Schocher } 838f64da7fSHeiko Schocher return 0; 848f64da7fSHeiko Schocher } 858f64da7fSHeiko Schocher 868f64da7fSHeiko Schocher static int ivm_get_value (unsigned char *buf, int len, char *name, int off, 878f64da7fSHeiko Schocher int check) 888f64da7fSHeiko Schocher { 898f64da7fSHeiko Schocher unsigned short val; 908f64da7fSHeiko Schocher unsigned char valbuf[30]; 918f64da7fSHeiko Schocher 928f64da7fSHeiko Schocher if ((buf[off + 0] != buf[off + 2]) && 938f64da7fSHeiko Schocher (buf[off + 2] != buf[off + 4])) { 948f64da7fSHeiko Schocher printf ("%s Error corrupted %s\n", __FUNCTION__, name); 958f64da7fSHeiko Schocher val = -1; 968f64da7fSHeiko Schocher } else { 978f64da7fSHeiko Schocher val = buf[off + 0] + (buf[off + 1] << 8); 988f64da7fSHeiko Schocher if ((val == 0) && (check == 1)) 998f64da7fSHeiko Schocher val = -1; 1008f64da7fSHeiko Schocher } 1018f64da7fSHeiko Schocher sprintf ((char *)valbuf, "%x", val); 1028f64da7fSHeiko Schocher ivm_set_value (name, (char *)valbuf); 1038f64da7fSHeiko Schocher return val; 1048f64da7fSHeiko Schocher } 1058f64da7fSHeiko Schocher 1068f64da7fSHeiko Schocher #define INVENTORYBLOCKSIZE 0x100 1078f64da7fSHeiko Schocher #define INVENTORYDATAADDRESS 0x21 1088f64da7fSHeiko Schocher #define INVENTORYDATASIZE (INVENTORYBLOCKSIZE - INVENTORYDATAADDRESS - 3) 1098f64da7fSHeiko Schocher 1108f64da7fSHeiko Schocher #define IVM_POS_SHORT_TEXT 0 1118f64da7fSHeiko Schocher #define IVM_POS_MANU_ID 1 1128f64da7fSHeiko Schocher #define IVM_POS_MANU_SERIAL 2 1138f64da7fSHeiko Schocher #define IVM_POS_PART_NUMBER 3 1148f64da7fSHeiko Schocher #define IVM_POS_BUILD_STATE 4 1158f64da7fSHeiko Schocher #define IVM_POS_SUPPLIER_PART_NUMBER 5 1168f64da7fSHeiko Schocher #define IVM_POS_DELIVERY_DATE 6 1178f64da7fSHeiko Schocher #define IVM_POS_SUPPLIER_BUILD_STATE 7 1188f64da7fSHeiko Schocher #define IVM_POS_CUSTOMER_ID 8 1198f64da7fSHeiko Schocher #define IVM_POS_CUSTOMER_PROD_ID 9 1208f64da7fSHeiko Schocher #define IVM_POS_HISTORY 10 1218f64da7fSHeiko Schocher #define IVM_POS_SYMBOL_ONLY 11 1228f64da7fSHeiko Schocher 1238f64da7fSHeiko Schocher static char convert_char (char c) 1248f64da7fSHeiko Schocher { 1258f64da7fSHeiko Schocher return (c < ' ' || c > '~') ? '.' : c; 1268f64da7fSHeiko Schocher } 1278f64da7fSHeiko Schocher 1288f64da7fSHeiko Schocher static int ivm_findinventorystring (int type, 1298f64da7fSHeiko Schocher unsigned char* const string, 1308f64da7fSHeiko Schocher unsigned long maxlen, 1318f64da7fSHeiko Schocher unsigned char *buf) 1328f64da7fSHeiko Schocher { 1338f64da7fSHeiko Schocher int xcode = 0; 1348f64da7fSHeiko Schocher unsigned long cr = 0; 1358f64da7fSHeiko Schocher unsigned long addr = INVENTORYDATAADDRESS; 1368f64da7fSHeiko Schocher unsigned long size = 0; 1378f64da7fSHeiko Schocher unsigned long nr = type; 1388f64da7fSHeiko Schocher int stop = 0; /* stop on semicolon */ 1398f64da7fSHeiko Schocher 1408f64da7fSHeiko Schocher memset(string, '\0', maxlen); 1418f64da7fSHeiko Schocher switch (type) { 1428f64da7fSHeiko Schocher case IVM_POS_SYMBOL_ONLY: 1438f64da7fSHeiko Schocher nr = 0; 1448f64da7fSHeiko Schocher stop= 1; 1458f64da7fSHeiko Schocher break; 1468f64da7fSHeiko Schocher default: 1478f64da7fSHeiko Schocher nr = type; 1488f64da7fSHeiko Schocher stop = 0; 1498f64da7fSHeiko Schocher } 1508f64da7fSHeiko Schocher 1518f64da7fSHeiko Schocher /* Look for the requested number of CR. */ 1528f64da7fSHeiko Schocher while ((cr != nr) && (addr < INVENTORYDATASIZE)) { 1538f64da7fSHeiko Schocher if ((buf[addr] == '\r')) { 1548f64da7fSHeiko Schocher cr++; 1558f64da7fSHeiko Schocher } 1568f64da7fSHeiko Schocher addr++; 1578f64da7fSHeiko Schocher } 1588f64da7fSHeiko Schocher 1598f64da7fSHeiko Schocher /* the expected number of CR was found until the end of the IVM 1608f64da7fSHeiko Schocher * content --> fill string */ 1618f64da7fSHeiko Schocher if (addr < INVENTORYDATASIZE) { 1628f64da7fSHeiko Schocher /* Copy the IVM string in the corresponding string */ 1638f64da7fSHeiko Schocher for (; (buf[addr] != '\r') && 1648f64da7fSHeiko Schocher ((buf[addr] != ';') || (!stop)) && 1658f64da7fSHeiko Schocher (size < (maxlen - 1) && 1668f64da7fSHeiko Schocher (addr < INVENTORYDATASIZE)); addr++) 1678f64da7fSHeiko Schocher { 1688f64da7fSHeiko Schocher size += sprintf((char *)string + size, "%c", 1698f64da7fSHeiko Schocher convert_char (buf[addr])); 1708f64da7fSHeiko Schocher } 1718f64da7fSHeiko Schocher 1728f64da7fSHeiko Schocher /* copy phase is done: check if everything is ok. If not, 1738f64da7fSHeiko Schocher * the inventory data is most probably corrupted: tell 1748f64da7fSHeiko Schocher * the world there is a problem! */ 1758f64da7fSHeiko Schocher if (addr == INVENTORYDATASIZE) { 1768f64da7fSHeiko Schocher xcode = -1; 1778f64da7fSHeiko Schocher printf ("Error end of string not found\n"); 1788f64da7fSHeiko Schocher } else if ((size >= (maxlen - 1)) && 1798f64da7fSHeiko Schocher (buf[addr] != '\r')) { 1808f64da7fSHeiko Schocher xcode = -1; 1818f64da7fSHeiko Schocher printf ("string too long till next CR\n"); 1828f64da7fSHeiko Schocher } 1838f64da7fSHeiko Schocher } else { 1848f64da7fSHeiko Schocher /* some CR are missing... 1858f64da7fSHeiko Schocher * the inventory data is most probably corrupted */ 1868f64da7fSHeiko Schocher xcode = -1; 1878f64da7fSHeiko Schocher printf ("not enough cr found\n"); 1888f64da7fSHeiko Schocher } 1898f64da7fSHeiko Schocher return xcode; 1908f64da7fSHeiko Schocher } 1918f64da7fSHeiko Schocher 1928f64da7fSHeiko Schocher #define GET_STRING(name, which, len) \ 1938f64da7fSHeiko Schocher if (ivm_findinventorystring (which, valbuf, len, buf) == 0) { \ 1948f64da7fSHeiko Schocher ivm_set_value (name, (char *)valbuf); \ 1958f64da7fSHeiko Schocher } 1968f64da7fSHeiko Schocher 1978f64da7fSHeiko Schocher static int ivm_check_crc (unsigned char *buf, int block) 1988f64da7fSHeiko Schocher { 1998f64da7fSHeiko Schocher unsigned long crc; 2008f64da7fSHeiko Schocher unsigned long crceeprom; 2018f64da7fSHeiko Schocher 2026d0f6bcfSJean-Christophe PLAGNIOL-VILLARD crc = ivm_calc_crc (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2); 2036d0f6bcfSJean-Christophe PLAGNIOL-VILLARD crceeprom = (buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 1] + \ 2046d0f6bcfSJean-Christophe PLAGNIOL-VILLARD buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2] * 256); 2058f64da7fSHeiko Schocher if (crc != crceeprom) { 206*dc71b248SHeiko Schocher if (block == 0) 207*dc71b248SHeiko Schocher printf ("Error CRC Block: %d EEprom: calculated: \ 208*dc71b248SHeiko Schocher %lx EEprom: %lx\n", block, crc, crceeprom); 2098f64da7fSHeiko Schocher return -1; 2108f64da7fSHeiko Schocher } 2118f64da7fSHeiko Schocher return 0; 2128f64da7fSHeiko Schocher } 2138f64da7fSHeiko Schocher 2148f64da7fSHeiko Schocher static int ivm_analyze_block2 (unsigned char *buf, int len) 2158f64da7fSHeiko Schocher { 2166d0f6bcfSJean-Christophe PLAGNIOL-VILLARD unsigned char valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN]; 2178f64da7fSHeiko Schocher unsigned long count; 2188f64da7fSHeiko Schocher 2198f64da7fSHeiko Schocher /* IVM_MacAddress */ 2208f64da7fSHeiko Schocher sprintf ((char *)valbuf, "%02X:%02X:%02X:%02X:%02X:%02X", 2218f64da7fSHeiko Schocher buf[1], 2228f64da7fSHeiko Schocher buf[2], 2238f64da7fSHeiko Schocher buf[3], 2248f64da7fSHeiko Schocher buf[4], 2258f64da7fSHeiko Schocher buf[5], 2268f64da7fSHeiko Schocher buf[6]); 2278f64da7fSHeiko Schocher ivm_set_value ("IVM_MacAddress", (char *)valbuf); 2288f64da7fSHeiko Schocher if (getenv ("ethaddr") == NULL) 2298f64da7fSHeiko Schocher setenv ((char *)"ethaddr", (char *)valbuf); 2308f64da7fSHeiko Schocher /* IVM_MacCount */ 2318f64da7fSHeiko Schocher count = (buf[10] << 24) + 2328f64da7fSHeiko Schocher (buf[11] << 16) + 2338f64da7fSHeiko Schocher (buf[12] << 8) + 2348f64da7fSHeiko Schocher buf[13]; 2358f64da7fSHeiko Schocher if (count == 0xffffffff) 2368f64da7fSHeiko Schocher count = 1; 2378f64da7fSHeiko Schocher sprintf ((char *)valbuf, "%lx", count); 2388f64da7fSHeiko Schocher ivm_set_value ("IVM_MacCount", (char *)valbuf); 2398f64da7fSHeiko Schocher return 0; 2408f64da7fSHeiko Schocher } 2418f64da7fSHeiko Schocher 2428f64da7fSHeiko Schocher int ivm_analyze_eeprom (unsigned char *buf, int len) 2438f64da7fSHeiko Schocher { 2448f64da7fSHeiko Schocher unsigned short val; 2456d0f6bcfSJean-Christophe PLAGNIOL-VILLARD unsigned char valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN]; 2468f64da7fSHeiko Schocher unsigned char *tmp; 2478f64da7fSHeiko Schocher 2488f64da7fSHeiko Schocher if (ivm_check_crc (buf, 0) != 0) 2498f64da7fSHeiko Schocher return -1; 2508f64da7fSHeiko Schocher 2516d0f6bcfSJean-Christophe PLAGNIOL-VILLARD ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_BoardId", 0, 1); 2526d0f6bcfSJean-Christophe PLAGNIOL-VILLARD val = ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_HWKey", 6, 1); 2538f64da7fSHeiko Schocher if (val != 0xffff) { 2548f64da7fSHeiko Schocher sprintf ((char *)valbuf, "%x", ((val /100) % 10)); 2558f64da7fSHeiko Schocher ivm_set_value ("IVM_HWVariant", (char *)valbuf); 2568f64da7fSHeiko Schocher sprintf ((char *)valbuf, "%x", (val % 100)); 2578f64da7fSHeiko Schocher ivm_set_value ("IVM_HWVersion", (char *)valbuf); 2588f64da7fSHeiko Schocher } 2596d0f6bcfSJean-Christophe PLAGNIOL-VILLARD ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_Functions", 12, 0); 2608f64da7fSHeiko Schocher 2618f64da7fSHeiko Schocher GET_STRING("IVM_Symbol", IVM_POS_SYMBOL_ONLY, 8) 2628f64da7fSHeiko Schocher GET_STRING("IVM_DeviceName", IVM_POS_SHORT_TEXT, 64) 2638f64da7fSHeiko Schocher tmp = (unsigned char *) getenv("IVM_DeviceName"); 2648f64da7fSHeiko Schocher if (tmp) { 2658f64da7fSHeiko Schocher int len = strlen ((char *)tmp); 2668f64da7fSHeiko Schocher int i = 0; 2678f64da7fSHeiko Schocher 2688f64da7fSHeiko Schocher while (i < len) { 2698f64da7fSHeiko Schocher if (tmp[i] == ';') { 2708f64da7fSHeiko Schocher ivm_set_value ("IVM_ShortText", (char *)&tmp[i + 1]); 2718f64da7fSHeiko Schocher break; 2728f64da7fSHeiko Schocher } 2738f64da7fSHeiko Schocher i++; 2748f64da7fSHeiko Schocher } 2758f64da7fSHeiko Schocher if (i >= len) 2768f64da7fSHeiko Schocher ivm_set_value ("IVM_ShortText", NULL); 2778f64da7fSHeiko Schocher } else { 2788f64da7fSHeiko Schocher ivm_set_value ("IVM_ShortText", NULL); 2798f64da7fSHeiko Schocher } 2808f64da7fSHeiko Schocher GET_STRING("IVM_ManufacturerID", IVM_POS_MANU_ID, 32) 2818f64da7fSHeiko Schocher GET_STRING("IVM_ManufacturerSerialNumber", IVM_POS_MANU_SERIAL, 20) 2828f64da7fSHeiko Schocher GET_STRING("IVM_ManufacturerPartNumber", IVM_POS_PART_NUMBER, 32) 2838f64da7fSHeiko Schocher GET_STRING("IVM_ManufacturerBuildState", IVM_POS_BUILD_STATE, 32) 2848f64da7fSHeiko Schocher GET_STRING("IVM_SupplierPartNumber", IVM_POS_SUPPLIER_PART_NUMBER, 32) 2858f64da7fSHeiko Schocher GET_STRING("IVM_DelieveryDate", IVM_POS_DELIVERY_DATE, 32) 2868f64da7fSHeiko Schocher GET_STRING("IVM_SupplierBuildState", IVM_POS_SUPPLIER_BUILD_STATE, 32) 2878f64da7fSHeiko Schocher GET_STRING("IVM_CustomerID", IVM_POS_CUSTOMER_ID, 32) 2888f64da7fSHeiko Schocher GET_STRING("IVM_CustomerProductID", IVM_POS_CUSTOMER_PROD_ID, 32) 2898f64da7fSHeiko Schocher 2906d0f6bcfSJean-Christophe PLAGNIOL-VILLARD if (ivm_check_crc (&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], 2) != 0) 291*dc71b248SHeiko Schocher return 0; 2926d0f6bcfSJean-Christophe PLAGNIOL-VILLARD ivm_analyze_block2 (&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], CONFIG_SYS_IVM_EEPROM_PAGE_LEN); 2938f64da7fSHeiko Schocher 2948f64da7fSHeiko Schocher return 0; 2958f64da7fSHeiko Schocher } 2968f64da7fSHeiko Schocher 2978f64da7fSHeiko Schocher int ivm_read_eeprom (void) 2988f64da7fSHeiko Schocher { 2991b6275dfSHeiko Schocher #if defined(CONFIG_I2C_MUX) 3008f64da7fSHeiko Schocher I2C_MUX_DEVICE *dev = NULL; 3011b6275dfSHeiko Schocher #endif 3026d0f6bcfSJean-Christophe PLAGNIOL-VILLARD uchar i2c_buffer[CONFIG_SYS_IVM_EEPROM_MAX_LEN]; 3038f64da7fSHeiko Schocher uchar *buf; 3046d0f6bcfSJean-Christophe PLAGNIOL-VILLARD unsigned dev_addr = CONFIG_SYS_IVM_EEPROM_ADR; 3058f64da7fSHeiko Schocher 3061b6275dfSHeiko Schocher #if defined(CONFIG_I2C_MUX) 3078f64da7fSHeiko Schocher /* First init the Bus, select the Bus */ 3086d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_I2C_IVM_BUS) 3096d0f6bcfSJean-Christophe PLAGNIOL-VILLARD dev = i2c_mux_ident_muxstring ((uchar *)CONFIG_SYS_I2C_IVM_BUS); 3108f64da7fSHeiko Schocher #else 3118f64da7fSHeiko Schocher buf = (unsigned char *) getenv ("EEprom_ivm"); 3128f64da7fSHeiko Schocher if (buf != NULL) 3138f64da7fSHeiko Schocher dev = i2c_mux_ident_muxstring (buf); 3148f64da7fSHeiko Schocher #endif 3158f64da7fSHeiko Schocher if (dev == NULL) { 3168f64da7fSHeiko Schocher printf ("Error couldnt add Bus for IVM\n"); 3178f64da7fSHeiko Schocher return -1; 3188f64da7fSHeiko Schocher } 3198f64da7fSHeiko Schocher i2c_set_bus_num (dev->busid); 3201b6275dfSHeiko Schocher #endif 3218f64da7fSHeiko Schocher 3228f64da7fSHeiko Schocher buf = (unsigned char *) getenv ("EEprom_ivm_addr"); 3238f64da7fSHeiko Schocher if (buf != NULL) 3248f64da7fSHeiko Schocher dev_addr = simple_strtoul ((char *)buf, NULL, 16); 3258f64da7fSHeiko Schocher 32619f0e930SHeiko Schocher if (i2c_read(dev_addr, 0, 1, i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN) != 0) { 3278f64da7fSHeiko Schocher printf ("Error reading EEprom\n"); 3288f64da7fSHeiko Schocher return -2; 3298f64da7fSHeiko Schocher } 3308f64da7fSHeiko Schocher 3316d0f6bcfSJean-Christophe PLAGNIOL-VILLARD return ivm_analyze_eeprom (i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN); 3328f64da7fSHeiko Schocher } 3338f64da7fSHeiko Schocher 3346d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_SYS_I2C_INIT_BOARD) 335c2485364SHeiko Schocher #define DELAY_ABORT_SEQ 62 3366d0f6bcfSJean-Christophe PLAGNIOL-VILLARD #define DELAY_HALF_PERIOD (500 / (CONFIG_SYS_I2C_SPEED / 1000)) 337c2485364SHeiko Schocher 338c2485364SHeiko Schocher #if defined(CONFIG_MGCOGE) 339c2485364SHeiko Schocher #define SDA_MASK 0x00010000 340c2485364SHeiko Schocher #define SCL_MASK 0x00020000 341c2485364SHeiko Schocher static void set_pin (int state, unsigned long mask) 342c2485364SHeiko Schocher { 3436d0f6bcfSJean-Christophe PLAGNIOL-VILLARD volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3); 344c2485364SHeiko Schocher 345c2485364SHeiko Schocher if (state) 346c2485364SHeiko Schocher iop->pdat |= (mask); 347c2485364SHeiko Schocher else 348c2485364SHeiko Schocher iop->pdat &= ~(mask); 349c2485364SHeiko Schocher 350c2485364SHeiko Schocher iop->pdir |= (mask); 351c2485364SHeiko Schocher } 352c2485364SHeiko Schocher 353c2485364SHeiko Schocher static int get_pin (unsigned long mask) 354c2485364SHeiko Schocher { 3556d0f6bcfSJean-Christophe PLAGNIOL-VILLARD volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3); 356c2485364SHeiko Schocher 357c2485364SHeiko Schocher iop->pdir &= ~(mask); 358c2485364SHeiko Schocher return (0 != (iop->pdat & (mask))); 359c2485364SHeiko Schocher } 360c2485364SHeiko Schocher 361c2485364SHeiko Schocher static void set_sda (int state) 362c2485364SHeiko Schocher { 363c2485364SHeiko Schocher set_pin (state, SDA_MASK); 364c2485364SHeiko Schocher } 365c2485364SHeiko Schocher 366c2485364SHeiko Schocher static void set_scl (int state) 367c2485364SHeiko Schocher { 368c2485364SHeiko Schocher set_pin (state, SCL_MASK); 369c2485364SHeiko Schocher } 370c2485364SHeiko Schocher 371c2485364SHeiko Schocher static int get_sda (void) 372c2485364SHeiko Schocher { 373c2485364SHeiko Schocher return get_pin (SDA_MASK); 374c2485364SHeiko Schocher } 375c2485364SHeiko Schocher 376c2485364SHeiko Schocher static int get_scl (void) 377c2485364SHeiko Schocher { 378c2485364SHeiko Schocher return get_pin (SCL_MASK); 379c2485364SHeiko Schocher } 380c2485364SHeiko Schocher 381c2485364SHeiko Schocher #if defined(CONFIG_HARD_I2C) 382c2485364SHeiko Schocher static void setports (int gpio) 383c2485364SHeiko Schocher { 3846d0f6bcfSJean-Christophe PLAGNIOL-VILLARD volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3); 385c2485364SHeiko Schocher 386c2485364SHeiko Schocher if (gpio) { 387c2485364SHeiko Schocher iop->ppar &= ~(SDA_MASK | SCL_MASK); 388c2485364SHeiko Schocher iop->podr &= ~(SDA_MASK | SCL_MASK); 389c2485364SHeiko Schocher } else { 390c2485364SHeiko Schocher iop->ppar |= (SDA_MASK | SCL_MASK); 391c2485364SHeiko Schocher iop->pdir &= ~(SDA_MASK | SCL_MASK); 392c2485364SHeiko Schocher iop->podr |= (SDA_MASK | SCL_MASK); 393c2485364SHeiko Schocher } 394c2485364SHeiko Schocher } 395c2485364SHeiko Schocher #endif 396c2485364SHeiko Schocher #endif 397c2485364SHeiko Schocher 398d044954fSHeiko Schocher #if defined(CONFIG_KM8XX) 399c2485364SHeiko Schocher static void set_sda (int state) 400c2485364SHeiko Schocher { 401c2485364SHeiko Schocher I2C_SDA(state); 402c2485364SHeiko Schocher } 403c2485364SHeiko Schocher 404c2485364SHeiko Schocher static void set_scl (int state) 405c2485364SHeiko Schocher { 406c2485364SHeiko Schocher I2C_SCL(state); 407c2485364SHeiko Schocher } 408c2485364SHeiko Schocher 409c2485364SHeiko Schocher static int get_sda (void) 410c2485364SHeiko Schocher { 411a21ca95fSHeiko Schocher return I2C_READ; 412c2485364SHeiko Schocher } 413c2485364SHeiko Schocher 414c2485364SHeiko Schocher static int get_scl (void) 415c2485364SHeiko Schocher { 416c2485364SHeiko Schocher int val; 417c2485364SHeiko Schocher 418c2485364SHeiko Schocher *(unsigned short *)(I2C_BASE_DIR) &= ~SCL_CONF; 419c2485364SHeiko Schocher udelay (1); 420c2485364SHeiko Schocher val = *(unsigned char *)(I2C_BASE_PORT); 421c2485364SHeiko Schocher 422c2485364SHeiko Schocher return ((val & SCL_BIT) == SCL_BIT); 423c2485364SHeiko Schocher } 424c2485364SHeiko Schocher 425c2485364SHeiko Schocher #endif 426c2485364SHeiko Schocher 427c2485364SHeiko Schocher static void writeStartSeq (void) 428c2485364SHeiko Schocher { 429c2485364SHeiko Schocher set_sda (1); 430c2485364SHeiko Schocher udelay (DELAY_HALF_PERIOD); 431c2485364SHeiko Schocher set_scl (1); 432c2485364SHeiko Schocher udelay (DELAY_HALF_PERIOD); 433c2485364SHeiko Schocher set_sda (0); 434c2485364SHeiko Schocher udelay (DELAY_HALF_PERIOD); 435c2485364SHeiko Schocher set_scl (0); 436c2485364SHeiko Schocher udelay (DELAY_HALF_PERIOD); 437c2485364SHeiko Schocher } 438c2485364SHeiko Schocher 439c2485364SHeiko Schocher /* I2C is a synchronous protocol and resets of the processor in the middle 440c2485364SHeiko Schocher of an access can block the I2C Bus until a powerdown of the full unit is 441c2485364SHeiko Schocher done. This function toggles the SCL until the SCL and SCA line are 442c2485364SHeiko Schocher released, but max. 16 times, after this a I2C start-sequence is sent. 443c2485364SHeiko Schocher This I2C Deblocking mechanism was developed by Keymile in association 444c2485364SHeiko Schocher with Anatech and Atmel in 1998. 445c2485364SHeiko Schocher */ 446c2485364SHeiko Schocher static int i2c_make_abort (void) 447c2485364SHeiko Schocher { 448c2485364SHeiko Schocher int scl_state = 0; 449c2485364SHeiko Schocher int sda_state = 0; 450c2485364SHeiko Schocher int i = 0; 451c2485364SHeiko Schocher int ret = 0; 452c2485364SHeiko Schocher 453c2485364SHeiko Schocher if (!get_sda ()) { 454c2485364SHeiko Schocher ret = -1; 455c2485364SHeiko Schocher while (i < 16) { 456c2485364SHeiko Schocher i++; 457c2485364SHeiko Schocher set_scl (0); 458c2485364SHeiko Schocher udelay (DELAY_ABORT_SEQ); 459c2485364SHeiko Schocher set_scl (1); 460c2485364SHeiko Schocher udelay (DELAY_ABORT_SEQ); 461c2485364SHeiko Schocher scl_state = get_scl (); 462c2485364SHeiko Schocher sda_state = get_sda (); 463c2485364SHeiko Schocher if (scl_state && sda_state) { 464c2485364SHeiko Schocher ret = 0; 465c2485364SHeiko Schocher break; 466c2485364SHeiko Schocher } 467c2485364SHeiko Schocher } 468c2485364SHeiko Schocher } 469c2485364SHeiko Schocher if (ret == 0) { 470c2485364SHeiko Schocher for (i =0; i < 5; i++) { 471c2485364SHeiko Schocher writeStartSeq (); 472c2485364SHeiko Schocher } 473c2485364SHeiko Schocher } 474c2485364SHeiko Schocher get_sda (); 475c2485364SHeiko Schocher return ret; 476c2485364SHeiko Schocher } 477c2485364SHeiko Schocher 478c2485364SHeiko Schocher /** 479c2485364SHeiko Schocher * i2c_init_board - reset i2c bus. When the board is powercycled during a 480c2485364SHeiko Schocher * bus transfer it might hang; for details see doc/I2C_Edge_Conditions. 481c2485364SHeiko Schocher */ 482c2485364SHeiko Schocher void i2c_init_board(void) 483c2485364SHeiko Schocher { 484c2485364SHeiko Schocher #if defined(CONFIG_HARD_I2C) 4856d0f6bcfSJean-Christophe PLAGNIOL-VILLARD volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ; 486c2485364SHeiko Schocher volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c; 487c2485364SHeiko Schocher 488c2485364SHeiko Schocher /* disable I2C controller first, otherwhise it thinks we want to */ 489c2485364SHeiko Schocher /* talk to the slave port... */ 490c2485364SHeiko Schocher i2c->i2c_i2mod &= ~0x01; 491c2485364SHeiko Schocher 492c2485364SHeiko Schocher /* Set the PortPins to GPIO */ 493c2485364SHeiko Schocher setports (1); 494c2485364SHeiko Schocher #endif 495c2485364SHeiko Schocher 496c2485364SHeiko Schocher /* Now run the AbortSequence() */ 497c2485364SHeiko Schocher i2c_make_abort (); 498c2485364SHeiko Schocher 499c2485364SHeiko Schocher #if defined(CONFIG_HARD_I2C) 500c2485364SHeiko Schocher /* Set the PortPins back to use for I2C */ 501c2485364SHeiko Schocher setports (0); 502c2485364SHeiko Schocher #endif 503c2485364SHeiko Schocher } 504c2485364SHeiko Schocher #endif 505210c8c00SHeiko Schocher #endif 5066250f0f6SHeiko Schocher 5076250f0f6SHeiko Schocher #if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT) 5086250f0f6SHeiko Schocher int fdt_set_node_and_value (void *blob, 5096250f0f6SHeiko Schocher char *nodename, 5106250f0f6SHeiko Schocher char *regname, 5116250f0f6SHeiko Schocher void *var, 5126250f0f6SHeiko Schocher int size) 5136250f0f6SHeiko Schocher { 5146250f0f6SHeiko Schocher int ret = 0; 5156250f0f6SHeiko Schocher int nodeoffset = 0; 5166250f0f6SHeiko Schocher 5176250f0f6SHeiko Schocher nodeoffset = fdt_path_offset (blob, nodename); 5186250f0f6SHeiko Schocher if (nodeoffset >= 0) { 5196250f0f6SHeiko Schocher ret = fdt_setprop (blob, nodeoffset, regname, var, 5206250f0f6SHeiko Schocher size); 5216250f0f6SHeiko Schocher if (ret < 0) 5226250f0f6SHeiko Schocher printf("ft_blob_update(): cannot set %s/%s " 5236250f0f6SHeiko Schocher "property err:%s\n", nodename, regname, 5246250f0f6SHeiko Schocher fdt_strerror (ret)); 5256250f0f6SHeiko Schocher } else { 5266250f0f6SHeiko Schocher printf("ft_blob_update(): cannot find %s node " 5276250f0f6SHeiko Schocher "err:%s\n", nodename, fdt_strerror (nodeoffset)); 5286250f0f6SHeiko Schocher } 5296250f0f6SHeiko Schocher return ret; 5306250f0f6SHeiko Schocher } 531*dc71b248SHeiko Schocher int fdt_get_node_and_value (void *blob, 532*dc71b248SHeiko Schocher char *nodename, 533*dc71b248SHeiko Schocher char *propname, 534*dc71b248SHeiko Schocher void **var) 535*dc71b248SHeiko Schocher { 536*dc71b248SHeiko Schocher int len; 537*dc71b248SHeiko Schocher int nodeoffset = 0; 538*dc71b248SHeiko Schocher 539*dc71b248SHeiko Schocher nodeoffset = fdt_path_offset (blob, nodename); 540*dc71b248SHeiko Schocher if (nodeoffset >= 0) { 541*dc71b248SHeiko Schocher *var = (void *)fdt_getprop (blob, nodeoffset, propname, &len); 542*dc71b248SHeiko Schocher if (len == 0) { 543*dc71b248SHeiko Schocher /* no value */ 544*dc71b248SHeiko Schocher printf ("%s no value\n", __FUNCTION__); 545*dc71b248SHeiko Schocher return -1; 546*dc71b248SHeiko Schocher } else if (len > 0) { 547*dc71b248SHeiko Schocher return len; 548*dc71b248SHeiko Schocher } else { 549*dc71b248SHeiko Schocher printf ("libfdt fdt_getprop(): %s\n", 550*dc71b248SHeiko Schocher fdt_strerror(len)); 551*dc71b248SHeiko Schocher return -2; 552*dc71b248SHeiko Schocher } 553*dc71b248SHeiko Schocher } else { 554*dc71b248SHeiko Schocher printf("%s: cannot find %s node err:%s\n", __FUNCTION__, 555*dc71b248SHeiko Schocher nodename, fdt_strerror (nodeoffset)); 556*dc71b248SHeiko Schocher return -3; 557*dc71b248SHeiko Schocher } 558*dc71b248SHeiko Schocher } 5596250f0f6SHeiko Schocher #endif 560210c8c00SHeiko Schocher 561210c8c00SHeiko Schocher int ethernet_present (void) 562210c8c00SHeiko Schocher { 563210c8c00SHeiko Schocher return (in_8((u8 *)CONFIG_SYS_PIGGY_BASE + CONFIG_SYS_SLOT_ID_OFF) & 0x80); 564210c8c00SHeiko Schocher } 565210c8c00SHeiko Schocher 566210c8c00SHeiko Schocher int board_eth_init (bd_t *bis) 567210c8c00SHeiko Schocher { 568210c8c00SHeiko Schocher #ifdef CONFIG_KEYMILE_HDLC_ENET 569210c8c00SHeiko Schocher (void)keymile_hdlc_enet_initialize (bis); 570210c8c00SHeiko Schocher #endif 571210c8c00SHeiko Schocher if (ethernet_present ()) { 572210c8c00SHeiko Schocher return -1; 573210c8c00SHeiko Schocher } 574210c8c00SHeiko Schocher return 0; 575210c8c00SHeiko Schocher } 576