summaryrefslogtreecommitdiffstats
path: root/board/corscience
diff options
context:
space:
mode:
Diffstat (limited to 'board/corscience')
-rw-r--r--board/corscience/tricorder/Makefile2
-rw-r--r--board/corscience/tricorder/led.c80
-rw-r--r--board/corscience/tricorder/tricorder-eeprom.c251
-rw-r--r--board/corscience/tricorder/tricorder-eeprom.h41
-rw-r--r--board/corscience/tricorder/tricorder.c126
-rw-r--r--board/corscience/tricorder/tricorder.h4
6 files changed, 492 insertions, 12 deletions
diff --git a/board/corscience/tricorder/Makefile b/board/corscience/tricorder/Makefile
index d5316f8d38..266432dd2d 100644
--- a/board/corscience/tricorder/Makefile
+++ b/board/corscience/tricorder/Makefile
@@ -8,4 +8,4 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-y := tricorder.o
+obj-y := tricorder.o tricorder-eeprom.o led.o
diff --git a/board/corscience/tricorder/led.c b/board/corscience/tricorder/led.c
new file mode 100644
index 0000000000..30f2f508f0
--- /dev/null
+++ b/board/corscience/tricorder/led.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013 Corscience GmbH & Co.KG
+ * Andreas Bießmann <andreas.biessmann@corscience.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <status_led.h>
+#include <twl4030.h>
+#include <asm/arch/cpu.h>
+#include <asm/io.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/gpio.h>
+
+#define TRICORDER_STATUS_LED_YELLOW 42
+#define TRICORDER_STATUS_LED_GREEN 43
+
+void __led_init(led_id_t mask, int state)
+{
+ __led_set(mask, state);
+}
+
+void __led_toggle(led_id_t mask)
+{
+ int toggle_gpio = 0;
+#ifdef STATUS_LED_BIT
+ if (!toggle_gpio && STATUS_LED_BIT & mask)
+ toggle_gpio = TRICORDER_STATUS_LED_GREEN;
+#endif
+#ifdef STATUS_LED_BIT1
+ if (!toggle_gpio && STATUS_LED_BIT1 & mask)
+ toggle_gpio = TRICORDER_STATUS_LED_YELLOW;
+#endif
+#ifdef STATUS_LED_BIT2
+ if (!toggle_gpio && STATUS_LED_BIT2 & mask) {
+ uint8_t val;
+ twl4030_i2c_read_u8(TWL4030_CHIP_LED, TWL4030_LED_LEDEN,
+ &val);
+ val ^= (TWL4030_LED_LEDEN_LEDAON | TWL4030_LED_LEDEN_LEDAPWM);
+ twl4030_i2c_write_u8(TWL4030_CHIP_LED, TWL4030_LED_LEDEN,
+ val);
+ }
+#endif
+ if (toggle_gpio) {
+ int state;
+ gpio_request(toggle_gpio, "");
+ state = gpio_get_value(toggle_gpio);
+ gpio_set_value(toggle_gpio, !state);
+ }
+}
+
+void __led_set(led_id_t mask, int state)
+{
+#ifdef STATUS_LED_BIT
+ if (STATUS_LED_BIT & mask) {
+ gpio_request(TRICORDER_STATUS_LED_GREEN, "");
+ gpio_direction_output(TRICORDER_STATUS_LED_GREEN, 0);
+ gpio_set_value(TRICORDER_STATUS_LED_GREEN, state);
+ }
+#endif
+#ifdef STATUS_LED_BIT1
+ if (STATUS_LED_BIT1 & mask) {
+ gpio_request(TRICORDER_STATUS_LED_YELLOW, "");
+ gpio_direction_output(TRICORDER_STATUS_LED_YELLOW, 0);
+ gpio_set_value(TRICORDER_STATUS_LED_YELLOW, state);
+ }
+#endif
+#ifdef STATUS_LED_BIT2
+ if (STATUS_LED_BIT2 & mask) {
+ if (STATUS_LED_OFF == state)
+ twl4030_i2c_write_u8(TWL4030_CHIP_LED,
+ TWL4030_LED_LEDEN, 0);
+ else
+ twl4030_i2c_write_u8(TWL4030_CHIP_LED,
+ TWL4030_LED_LEDEN,
+ (TWL4030_LED_LEDEN_LEDAON |
+ TWL4030_LED_LEDEN_LEDAPWM));
+ }
+#endif
+}
diff --git a/board/corscience/tricorder/tricorder-eeprom.c b/board/corscience/tricorder/tricorder-eeprom.c
new file mode 100644
index 0000000000..1c74a0f7d0
--- /dev/null
+++ b/board/corscience/tricorder/tricorder-eeprom.c
@@ -0,0 +1,251 @@
+/*
+ * (C) Copyright 2013
+ * Corscience GmbH & Co. KG, <www.corscience.de>
+ * Andreas Bießmann <andreas.biessmann@corscience.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <i2c.h>
+
+#include "tricorder-eeprom.h"
+
+static inline void warn_wrong_value(const char *msg, unsigned int a,
+ unsigned int b)
+{
+ printf("Expected EEPROM %s %08x, got %08x\n", msg, a, b);
+}
+
+static int handle_eeprom_v0(struct tricorder_eeprom *eeprom)
+{
+ struct tricorder_eeprom_v0 {
+ uint32_t magic;
+ uint16_t length;
+ uint16_t version;
+ char board_name[TRICORDER_BOARD_NAME_LENGTH];
+ char board_version[TRICORDER_BOARD_VERSION_LENGTH];
+ char board_serial[TRICORDER_BOARD_SERIAL_LENGTH];
+ uint32_t crc32;
+ } __packed eepromv0;
+ uint32_t crc;
+
+ printf("Old EEPROM (v0), consider rewrite!\n");
+
+ if (be16_to_cpu(eeprom->length) != sizeof(eepromv0)) {
+ warn_wrong_value("length", sizeof(eepromv0),
+ be16_to_cpu(eeprom->length));
+ return 1;
+ }
+
+ memcpy(&eepromv0, eeprom, sizeof(eepromv0));
+
+ crc = crc32(0L, (unsigned char *)&eepromv0,
+ sizeof(eepromv0) - sizeof(eepromv0.crc32));
+ if (be32_to_cpu(eepromv0.crc32) != crc) {
+ warn_wrong_value("CRC", be32_to_cpu(eepromv0.crc32),
+ crc);
+ return 1;
+ }
+
+ /* Ok the content is correct, do the conversion */
+ memset(eeprom->interface_version, 0x0,
+ TRICORDER_INTERFACE_VERSION_LENGTH);
+ crc = crc32(0L, (unsigned char *)eeprom, TRICORDER_EEPROM_CRC_SIZE);
+ eeprom->crc32 = cpu_to_be32(crc);
+
+ return 0;
+}
+
+static int handle_eeprom_v1(struct tricorder_eeprom *eeprom)
+{
+ uint32_t crc;
+
+ if (be16_to_cpu(eeprom->length) != TRICORDER_EEPROM_SIZE) {
+ warn_wrong_value("length", TRICORDER_EEPROM_SIZE,
+ be16_to_cpu(eeprom->length));
+ return 1;
+ }
+
+ crc = crc32(0L, (unsigned char *)eeprom, TRICORDER_EEPROM_CRC_SIZE);
+ if (be32_to_cpu(eeprom->crc32) != crc) {
+ warn_wrong_value("CRC", be32_to_cpu(eeprom->crc32), crc);
+ return 1;
+ }
+
+ return 0;
+}
+
+int tricorder_get_eeprom(int addr, struct tricorder_eeprom *eeprom)
+{
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+ unsigned int bus = i2c_get_bus_num();
+ i2c_set_bus_num(CONFIG_SYS_EEPROM_BUS_NUM);
+#endif
+
+ memset(eeprom, 0, TRICORDER_EEPROM_SIZE);
+
+ i2c_read(addr, 0, 2, (unsigned char *)eeprom, TRICORDER_EEPROM_SIZE);
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+ i2c_set_bus_num(bus);
+#endif
+
+ if (be32_to_cpu(eeprom->magic) != TRICORDER_EEPROM_MAGIC) {
+ warn_wrong_value("magic", TRICORDER_EEPROM_MAGIC,
+ be32_to_cpu(eeprom->magic));
+ return 1;
+ }
+
+ switch (be16_to_cpu(eeprom->version)) {
+ case 0:
+ return handle_eeprom_v0(eeprom);
+ case 1:
+ return handle_eeprom_v1(eeprom);
+ default:
+ warn_wrong_value("version", TRICORDER_EEPROM_VERSION,
+ be16_to_cpu(eeprom->version));
+ return 1;
+ }
+}
+
+#if !defined(CONFIG_SPL)
+int tricorder_eeprom_read(unsigned devaddr)
+{
+ struct tricorder_eeprom eeprom;
+ int ret = tricorder_get_eeprom(devaddr, &eeprom);
+
+ if (ret)
+ return ret;
+
+ printf("Board type: %.*s\n",
+ sizeof(eeprom.board_name), eeprom.board_name);
+ printf("Board version: %.*s\n",
+ sizeof(eeprom.board_version), eeprom.board_version);
+ printf("Board serial: %.*s\n",
+ sizeof(eeprom.board_serial), eeprom.board_serial);
+ printf("Board interface version: %.*s\n",
+ sizeof(eeprom.interface_version),
+ eeprom.interface_version);
+
+ return ret;
+}
+
+int tricorder_eeprom_write(unsigned devaddr, const char *name,
+ const char *version, const char *serial, const char *interface)
+{
+ struct tricorder_eeprom eeprom, eeprom_verify;
+ size_t length;
+ uint32_t crc;
+ int ret;
+ unsigned char *p;
+ int i;
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+ unsigned int bus;
+#endif
+
+ memset(eeprom, 0, TRICORDER_EEPROM_SIZE);
+ memset(eeprom_verify, 0, TRICORDER_EEPROM_SIZE);
+
+ eeprom.magic = cpu_to_be32(TRICORDER_EEPROM_MAGIC);
+ eeprom.length = cpu_to_be16(TRICORDER_EEPROM_SIZE);
+ eeprom.version = cpu_to_be16(TRICORDER_EEPROM_VERSION);
+
+ length = min(sizeof(eeprom.board_name), strlen(name));
+ strncpy(eeprom.board_name, name, length);
+
+ length = min(sizeof(eeprom.board_version), strlen(version));
+ strncpy(eeprom.board_version, version, length);
+
+ length = min(sizeof(eeprom.board_serial), strlen(serial));
+ strncpy(eeprom.board_serial, serial, length);
+
+ if (interface) {
+ length = min(sizeof(eeprom.interface_version),
+ strlen(interface));
+ strncpy(eeprom.interface_version, interface, length);
+ }
+
+ crc = crc32(0L, (unsigned char *)&eeprom, TRICORDER_EEPROM_CRC_SIZE);
+ eeprom.crc32 = cpu_to_be32(crc);
+
+#if defined(DEBUG)
+ puts("Tricorder EEPROM content:\n");
+ print_buffer(0, &eeprom, 1, sizeof(eeprom), 16);
+#endif
+
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+ bus = i2c_get_bus_num();
+ i2c_set_bus_num(CONFIG_SYS_EEPROM_BUS_NUM);
+#endif
+
+ /* do page write to the eeprom */
+ for (i = 0, p = (unsigned char *)&eeprom;
+ i < sizeof(eeprom);
+ i += 32, p += 32) {
+ ret = i2c_write(devaddr, i, CONFIG_SYS_I2C_EEPROM_ADDR_LEN,
+ p, min(sizeof(eeprom) - i, 32));
+ if (ret)
+ break;
+ udelay(5000); /* 5ms write cycle timing */
+ }
+
+ ret = i2c_read(devaddr, 0, 2, (unsigned char *)&eeprom_verify,
+ TRICORDER_EEPROM_SIZE);
+
+ if (memcmp(&eeprom, &eeprom_verify, sizeof(eeprom)) != 0) {
+ printf("Tricorder: Could not verify EEPROM content!\n");
+ ret = 1;
+ }
+
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+ i2c_set_bus_num(bus);
+#endif
+ return ret;
+}
+
+int do_tricorder_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ if (argc == 3) {
+ ulong dev_addr = simple_strtoul(argv[2], NULL, 16);
+ eeprom_init();
+ if (strcmp(argv[1], "read") == 0) {
+ int rcode;
+
+ rcode = tricorder_eeprom_read(dev_addr);
+
+ return rcode;
+ }
+ } else if (argc == 6 || argc == 7) {
+ ulong dev_addr = simple_strtoul(argv[2], NULL, 16);
+ char *name = argv[3];
+ char *version = argv[4];
+ char *serial = argv[5];
+ char *interface = NULL;
+ eeprom_init();
+
+ if (argc == 7)
+ interface = argv[6];
+
+ if (strcmp(argv[1], "write") == 0) {
+ int rcode;
+
+ rcode = tricorder_eeprom_write(dev_addr, name, version,
+ serial, interface);
+
+ return rcode;
+ }
+ }
+
+ return CMD_RET_USAGE;
+}
+
+U_BOOT_CMD(
+ tricordereeprom, 7, 1, do_tricorder_eeprom,
+ "Tricorder EEPROM",
+ "read devaddr\n"
+ " - read Tricorder EEPROM at devaddr and print content\n"
+ "tricordereeprom write devaddr name version serial [interface]\n"
+ " - write Tricorder EEPROM at devaddr with 'name', 'version'"
+ "and 'serial'\n"
+ " optional add an HW interface parameter"
+);
+#endif /* CONFIG_SPL */
diff --git a/board/corscience/tricorder/tricorder-eeprom.h b/board/corscience/tricorder/tricorder-eeprom.h
new file mode 100644
index 0000000000..06ed9a5911
--- /dev/null
+++ b/board/corscience/tricorder/tricorder-eeprom.h
@@ -0,0 +1,41 @@
+/*
+ * (C) Copyright 2013
+ * Corscience GmbH & Co. KG, <www.corscience.de>
+ * Andreas Bießmann <andreas.biessmann@corscience.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#ifndef TRICORDER_EEPROM_H_
+#define TRICORDER_EEPROM_H_
+
+#include <linux/compiler.h>
+
+#define TRICORDER_EEPROM_MAGIC 0xc2a94f52
+#define TRICORDER_EEPROM_VERSION 1
+
+#define TRICORDER_BOARD_NAME_LENGTH 12
+#define TRICORDER_BOARD_VERSION_LENGTH 4
+#define TRICORDER_BOARD_SERIAL_LENGTH 12
+#define TRICORDER_INTERFACE_VERSION_LENGTH 4
+
+struct tricorder_eeprom {
+ uint32_t magic;
+ uint16_t length;
+ uint16_t version;
+ char board_name[TRICORDER_BOARD_NAME_LENGTH];
+ char board_version[TRICORDER_BOARD_VERSION_LENGTH];
+ char board_serial[TRICORDER_BOARD_SERIAL_LENGTH];
+ char interface_version[TRICORDER_INTERFACE_VERSION_LENGTH];
+ uint32_t crc32;
+} __packed;
+
+#define TRICORDER_EEPROM_SIZE sizeof(struct tricorder_eeprom)
+#define TRICORDER_EEPROM_CRC_SIZE (TRICORDER_EEPROM_SIZE - \
+ sizeof(uint32_t))
+
+/**
+ * @brief read eeprom information from a specific eeprom address
+ */
+int tricorder_get_eeprom(int addr, struct tricorder_eeprom *eeprom);
+
+#endif /* TRICORDER_EEPROM_H_ */
diff --git a/board/corscience/tricorder/tricorder.c b/board/corscience/tricorder/tricorder.c
index c7099e5e3a..2dfcb271d3 100644
--- a/board/corscience/tricorder/tricorder.c
+++ b/board/corscience/tricorder/tricorder.c
@@ -13,11 +13,13 @@
#include <common.h>
#include <twl4030.h>
#include <asm/io.h>
+#include <asm/gpio.h>
#include <asm/arch/mmc_host_def.h>
#include <asm/arch/mux.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/mem.h>
#include "tricorder.h"
+#include "tricorder-eeprom.h"
DECLARE_GLOBAL_DATA_PTR;
@@ -34,16 +36,91 @@ int board_init(void)
return 0;
}
+/**
+ * get_eeprom - read the eeprom
+ *
+ * @eeprom - pointer to a eeprom struct to fill
+ *
+ * This function will panic() on wrong EEPROM content
+ */
+static void get_eeprom(struct tricorder_eeprom *eeprom)
+{
+ int ret;
+
+ if (!eeprom)
+ panic("No eeprom given!\n");
+
+ ret = gpio_request(7, "BMS");
+ if (ret)
+ panic("gpio: requesting BMS pin failed\n");
+
+ ret = gpio_direction_input(7);
+ if (ret)
+ panic("gpio: set BMS as input failed\n");
+
+ ret = gpio_get_value(7);
+ if (ret < 0)
+ panic("gpio: get BMS pin state failed\n");
+
+ gpio_free(7);
+
+ if (ret == 0) {
+ /* BMS is _not_ set, do the EEPROM check */
+ ret = tricorder_get_eeprom(0x51, eeprom);
+ if (!ret) {
+ if (strncmp(eeprom->board_name, "CS10411", 7) != 0)
+ panic("Wrong board name '%.*s'\n",
+ sizeof(eeprom->board_name),
+ eeprom->board_name);
+ if (eeprom->board_version[0] < 'D')
+ panic("Wrong board version '%.*s'\n",
+ sizeof(eeprom->board_version),
+ eeprom->board_version);
+ } else {
+ panic("Could not get board revision\n");
+ }
+ }
+}
+
+/**
+ * print_hwversion - print out a HW version string
+ *
+ * @eeprom - pointer to the eeprom
+ */
+static void print_hwversion(struct tricorder_eeprom *eeprom)
+{
+ size_t len;
+ if (!eeprom)
+ panic("No eeprom given!");
+
+ printf("Board %.*s:%.*s serial %.*s",
+ sizeof(eeprom->board_name), eeprom->board_name,
+ sizeof(eeprom->board_version), eeprom->board_version,
+ sizeof(eeprom->board_serial), eeprom->board_serial);
+
+ len = strnlen(eeprom->interface_version,
+ sizeof(eeprom->interface_version));
+ if (len > 0)
+ printf(" HW interface version %.*s",
+ sizeof(eeprom->interface_version),
+ eeprom->interface_version);
+ puts("\n");
+}
+
/*
* Routine: misc_init_r
* Description: Configure board specific parts
*/
int misc_init_r(void)
{
+ struct tricorder_eeprom eeprom;
+ get_eeprom(&eeprom);
+ print_hwversion(&eeprom);
+
twl4030_power_init();
-#ifdef CONFIG_TWL4030_LED
- twl4030_led_init(TWL4030_LED_LEDEN_LEDAON | TWL4030_LED_LEDEN_LEDBON);
-#endif
+ status_led_set(0, STATUS_LED_ON);
+ status_led_set(1, STATUS_LED_ON);
+ status_led_set(2, STATUS_LED_ON);
dieid_num_r();
@@ -77,12 +154,43 @@ int board_mmc_init(bd_t *bis)
*/
void get_board_mem_timings(struct board_sdrc_timings *timings)
{
+ struct tricorder_eeprom eeprom;
+ get_eeprom(&eeprom);
+
/* General SDRC config */
- timings->mcfg = MICRON_V_MCFG_165(128 << 20);
- timings->rfr_ctrl = SDP_3430_SDRC_RFR_CTRL_165MHz;
+ if (eeprom.board_version[0] > 'D') {
+ /* use optimized timings for our SDRAM device */
+ timings->mcfg = MCFG((256 << 20), 14);
+#define MT46H64M32_TDAL 6 /* Twr/Tck + Trp/tck */
+ /* 15/6 + 18/6 = 5.5 -> 6 */
+#define MT46H64M32_TDPL 3 /* 15/6 = 2.5 -> 3 (Twr) */
+#define MT46H64M32_TRRD 2 /* 12/6 = 2 */
+#define MT46H64M32_TRCD 3 /* 18/6 = 3 */
+#define MT46H64M32_TRP 3 /* 18/6 = 3 */
+#define MT46H64M32_TRAS 7 /* 42/6 = 7 */
+#define MT46H64M32_TRC 10 /* 60/6 = 10 */
+#define MT46H64M32_TRFC 12 /* 72/6 = 12 */
+ timings->ctrla = ACTIM_CTRLA(MT46H64M32_TRFC, MT46H64M32_TRC,
+ MT46H64M32_TRAS, MT46H64M32_TRP,
+ MT46H64M32_TRCD, MT46H64M32_TRRD,
+ MT46H64M32_TDPL,
+ MT46H64M32_TDAL);
+
+#define MT46H64M32_TWTR 1
+#define MT46H64M32_TCKE 1
+#define MT46H64M32_XSR 19 /* 112.5/6 = 18.75 => ~19 */
+#define MT46H64M32_TXP 1
+ timings->ctrlb = ACTIM_CTRLB(MT46H64M32_TWTR, MT46H64M32_TCKE,
+ MT46H64M32_TXP, MT46H64M32_XSR);
- /* AC timings */
- timings->ctrla = MICRON_V_ACTIMA_165;
- timings->ctrlb = MICRON_V_ACTIMB_165;
- timings->mr = MICRON_V_MR_165;
+ timings->mr = MICRON_V_MR_165;
+ timings->rfr_ctrl = SDP_3430_SDRC_RFR_CTRL_165MHz;
+ } else {
+ /* use conservative beagleboard timings as default */
+ timings->mcfg = MICRON_V_MCFG_165(128 << 20);
+ timings->ctrla = MICRON_V_ACTIMA_165;
+ timings->ctrlb = MICRON_V_ACTIMB_165;
+ timings->mr = MICRON_V_MR_165;
+ timings->rfr_ctrl = SDP_3430_SDRC_RFR_CTRL_165MHz;
+ }
}
diff --git a/board/corscience/tricorder/tricorder.h b/board/corscience/tricorder/tricorder.h
index 820a50c9f7..67c35c56bc 100644
--- a/board/corscience/tricorder/tricorder.h
+++ b/board/corscience/tricorder/tricorder.h
@@ -75,8 +75,8 @@ const omap3_sysinfo sysinfo = {
MUX_VAL(CP(GPMC_A6), (IDIS | PTD | DIS | M0)) /*GPMC_A6*/\
MUX_VAL(CP(GPMC_A7), (IDIS | PTD | DIS | M0)) /*GPMC_A7*/\
MUX_VAL(CP(GPMC_A8), (IDIS | PTD | DIS | M0)) /*GPMC_A8*/\
- MUX_VAL(CP(GPMC_A9), (IDIS | PTD | DIS | M0)) /*GPMC_A9*/\
- MUX_VAL(CP(GPMC_A10), (IDIS | PTD | DIS | M0)) /*GPMC_A10*/\
+ MUX_VAL(CP(GPMC_A9), (IDIS | PTU | EN | M4)) /*GPIO 42*/\
+ MUX_VAL(CP(GPMC_A10), (IDIS | PTU | EN | M4)) /*GPIO 43*/\
MUX_VAL(CP(GPMC_D0), (IEN | PTD | DIS | M0)) /*GPMC_D0*/\
MUX_VAL(CP(GPMC_D1), (IEN | PTD | DIS | M0)) /*GPMC_D1*/\
MUX_VAL(CP(GPMC_D2), (IEN | PTD | DIS | M0)) /*GPMC_D2*/\
OpenPOWER on IntegriCloud