blob: 7d2899dc94a30bc047c8ab76dac0e9ad3ec5ff99 [file] [log] [blame]
/*
* (C) Copyright 2010
* Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de
*
* based on kilauea.c
* by Stefan Roese, DENX Software Engineering, sr@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
*/
#include <common.h>
#include <asm/ppc4xx.h>
#include <asm/ppc405.h>
#include <libfdt.h>
#include <fdt_support.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <asm/errno.h>
#include <asm/ppc4xx-gpio.h>
#include <flash.h>
#include <pca9698.h>
#include "405ex.h"
#include <gdsys_fpga.h>
#include <miiphy.h>
#include <i2c.h>
#include <dtt.h>
DECLARE_GLOBAL_DATA_PTR;
#define PHYREG_CONTROL 0
#define PHYREG_PAGE_ADDRESS 22
#define PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1 16
#define PHYREG_PG2_COPPER_SPECIFIC_CONTROL_2 26
#define PHYREG_PG2_MAC_SPECIFIC_STATUS_1 17
#define PHYREG_PG2_MAC_SPECIFIC_CONTROL 21
#define LATCH0_BASE (CONFIG_SYS_LATCH_BASE)
#define LATCH1_BASE (CONFIG_SYS_LATCH_BASE + 0x100)
#define LATCH2_BASE (CONFIG_SYS_LATCH_BASE + 0x200)
#define LATCH3_BASE (CONFIG_SYS_LATCH_BASE + 0x300)
enum {
UNITTYPE_CCD_SWITCH = 1,
};
enum {
HWVER_100 = 0,
HWVER_110 = 1,
};
static inline void blank_string(int size)
{
int i;
for (i = 0; i < size; i++)
putc('\b');
for (i = 0; i < size; i++)
putc(' ');
for (i = 0; i < size; i++)
putc('\b');
}
/*
* Board early initialization function
*/
int misc_init_r(void)
{
/* startup fans */
dtt_init();
#ifdef CONFIG_ENV_IS_IN_FLASH
/* Monitor protection ON by default */
flash_protect(FLAG_PROTECT_SET,
-CONFIG_SYS_MONITOR_LEN,
0xffffffff,
&flash_info[0]);
#endif
return 0;
}
static void print_fpga_info(unsigned dev)
{
struct ihs_fpga *fpga = (struct ihs_fpga *) CONFIG_SYS_FPGA_BASE(dev);
u16 versions = in_le16(&fpga->versions);
u16 fpga_version = in_le16(&fpga->fpga_version);
u16 fpga_features = in_le16(&fpga->fpga_features);
int fpga_state = get_fpga_state(dev);
unsigned unit_type;
unsigned hardware_version;
unsigned feature_channels;
unsigned feature_expansion;
printf("FPGA%d: ", dev);
if (fpga_state & FPGA_STATE_PLATFORM)
printf("(legacy) ");
if (fpga_state & FPGA_STATE_DONE_FAILED) {
printf(" done timed out\n");
return;
}
if (fpga_state & FPGA_STATE_REFLECTION_FAILED) {
printf(" refelectione test failed\n");
return;
}
unit_type = (versions & 0xf000) >> 12;
hardware_version = versions & 0x000f;
feature_channels = fpga_features & 0x007f;
feature_expansion = fpga_features & (1<<15);
switch (unit_type) {
case UNITTYPE_CCD_SWITCH:
printf("CCD-Switch");
break;
default:
printf("UnitType %d(not supported)", unit_type);
break;
}
switch (hardware_version) {
case HWVER_100:
printf(" HW-Ver 1.00\n");
break;
case HWVER_110:
printf(" HW-Ver 1.10\n");
break;
default:
printf(" HW-Ver %d(not supported)\n",
hardware_version);
break;
}
printf(" FPGA V %d.%02d, features:",
fpga_version / 100, fpga_version % 100);
printf(" %d channel(s)", feature_channels);
printf(", expansion %ssupported\n", feature_expansion ? "" : "un");
}
int checkboard(void)
{
char *s = getenv("serial#");
printf("Board: CATCenter Io64\n");
if (s != NULL) {
puts(", serial# ");
puts(s);
}
return 0;
}
int configure_gbit_phy(char *bus, unsigned char addr)
{
unsigned short value;
/* select page 0 */
if (miiphy_write(bus, addr, PHYREG_PAGE_ADDRESS, 0x0000))
goto err_out;
/* switch to powerdown */
if (miiphy_read(bus, addr, PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1,
&value))
goto err_out;
if (miiphy_write(bus, addr, PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1,
value | 0x0004))
goto err_out;
/* select page 2 */
if (miiphy_write(bus, addr, PHYREG_PAGE_ADDRESS, 0x0002))
goto err_out;
/* disable SGMII autonegotiation */
if (miiphy_write(bus, addr, PHYREG_PG2_MAC_SPECIFIC_CONTROL, 48))
goto err_out;
/* select page 0 */
if (miiphy_write(bus, addr, PHYREG_PAGE_ADDRESS, 0x0000))
goto err_out;
/* switch from powerdown to normal operation */
if (miiphy_read(bus, addr, PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1,
&value))
goto err_out;
if (miiphy_write(bus, addr, PHYREG_PG0_COPPER_SPECIFIC_CONTROL_1,
value & ~0x0004))
goto err_out;
/* reset phy so settings take effect */
if (miiphy_write(bus, addr, PHYREG_CONTROL, 0x9140))
goto err_out;
return 0;
err_out:
printf("Error writing to the PHY addr=%02x\n", addr);
return -1;
}
int verify_gbit_phy(char *bus, unsigned char addr)
{
unsigned short value;
/* select page 2 */
if (miiphy_write(bus, addr, PHYREG_PAGE_ADDRESS, 0x0002))
goto err_out;
/* verify SGMII link status */
if (miiphy_read(bus, addr, PHYREG_PG2_MAC_SPECIFIC_STATUS_1, &value))
goto err_out;
if (!(value & (1 << 10)))
return -2;
return 0;
err_out:
printf("Error writing to the PHY addr=%02x\n", addr);
return -1;
}
int last_stage_init(void)
{
unsigned int k;
unsigned int fpga;
struct ihs_fpga *fpga0 = (struct ihs_fpga *) CONFIG_SYS_FPGA_BASE(0);
struct ihs_fpga *fpga1 = (struct ihs_fpga *) CONFIG_SYS_FPGA_BASE(1);
int failed = 0;
char str_phys[] = "Setup PHYs -";
char str_serdes[] = "Start SERDES blocks";
char str_channels[] = "Start FPGA channels";
char str_locks[] = "Verify SERDES locks";
char str_hicb[] = "Verify HICB status";
char str_status[] = "Verify PHY status -";
char slash[] = "\\|/-\\|/-";
print_fpga_info(0);
print_fpga_info(1);
/* setup Gbit PHYs */
puts("TRANS: ");
puts(str_phys);
miiphy_register(CONFIG_SYS_GBIT_MII_BUSNAME,
bb_miiphy_read, bb_miiphy_write);
for (k = 0; k < 32; ++k) {
configure_gbit_phy(CONFIG_SYS_GBIT_MII_BUSNAME, k);
putc('\b');
putc(slash[k % 8]);
}
miiphy_register(CONFIG_SYS_GBIT_MII1_BUSNAME,
bb_miiphy_read, bb_miiphy_write);
for (k = 0; k < 32; ++k) {
configure_gbit_phy(CONFIG_SYS_GBIT_MII1_BUSNAME, k);
putc('\b');
putc(slash[k % 8]);
}
blank_string(strlen(str_phys));
/* take fpga serdes blocks out of reset */
puts(str_serdes);
udelay(500000);
out_le16(&fpga0->quad_serdes_reset, 0);
out_le16(&fpga1->quad_serdes_reset, 0);
blank_string(strlen(str_serdes));
/* take channels out of reset */
puts(str_channels);
udelay(500000);
for (fpga = 0; fpga < 2; ++fpga) {
u16 *ch0_config_int = &(fpga ? fpga1 : fpga0)->ch0_config_int;
for (k = 0; k < 32; ++k)
out_le16(ch0_config_int + 4 * k, 0);
}
blank_string(strlen(str_channels));
/* verify channels serdes lock */
puts(str_locks);
udelay(500000);
for (fpga = 0; fpga < 2; ++fpga) {
u16 *ch0_status_int = &(fpga ? fpga1 : fpga0)->ch0_status_int;
for (k = 0; k < 32; ++k) {
u16 status = in_le16(ch0_status_int + 4*k);
if (!(status & (1 << 4))) {
failed = 1;
printf("fpga %d channel %d: no serdes lock\n",
fpga, k);
}
/* reset events */
out_le16(ch0_status_int + 4*k, status);
}
}
blank_string(strlen(str_locks));
/* verify hicb_status */
puts(str_hicb);
for (fpga = 0; fpga < 2; ++fpga) {
u16 *ch0_hicb_status_int = &(fpga ? fpga1 : fpga0)->ch0_hicb_status_int;
for (k = 0; k < 32; ++k) {
u16 status = in_le16(ch0_hicb_status_int + 4*k);
if (status)
printf("fpga %d hicb %d: hicb status %04x\n",
fpga, k, status);
/* reset events */
out_le16(ch0_hicb_status_int + 4*k, status);
}
}
blank_string(strlen(str_hicb));
/* verify phy status */
puts(str_status);
for (k = 0; k < 32; ++k) {
if (verify_gbit_phy(CONFIG_SYS_GBIT_MII_BUSNAME, k)) {
printf("verify baseboard phy %d failed\n", k);
failed = 1;
}
putc('\b');
putc(slash[k % 8]);
}
for (k = 0; k < 32; ++k) {
if (verify_gbit_phy(CONFIG_SYS_GBIT_MII1_BUSNAME, k)) {
printf("verify extensionboard phy %d failed\n", k);
failed = 1;
}
putc('\b');
putc(slash[k % 8]);
}
blank_string(strlen(str_status));
printf("Starting 64 channels %s\n", failed ? "failed" : "ok");
return 0;
}
void gd405ex_init(void)
{
unsigned int k;
if (i2c_probe(0x22)) { /* i2c_probe returns 0 on success */
for (k = 0; k < CONFIG_SYS_FPGA_COUNT; ++k)
gd->arch.fpga_state[k] |= FPGA_STATE_PLATFORM;
} else {
pca9698_direction_output(0x22, 39, 1);
}
}
void gd405ex_set_fpga_reset(unsigned state)
{
int legacy = get_fpga_state(0) & FPGA_STATE_PLATFORM;
if (legacy) {
if (state) {
out_le16((void *)LATCH0_BASE, CONFIG_SYS_LATCH0_RESET);
out_le16((void *)LATCH1_BASE, CONFIG_SYS_LATCH1_RESET);
} else {
out_le16((void *)LATCH0_BASE, CONFIG_SYS_LATCH0_BOOT);
out_le16((void *)LATCH1_BASE, CONFIG_SYS_LATCH1_BOOT);
}
} else {
pca9698_set_value(0x22, 39, state ? 0 : 1);
}
}
void gd405ex_setup_hw(void)
{
gpio_write_bit(CONFIG_SYS_GPIO_STARTUP_FINISHED_N, 0);
gpio_write_bit(CONFIG_SYS_GPIO_STARTUP_FINISHED, 1);
}
int gd405ex_get_fpga_done(unsigned fpga)
{
int legacy = get_fpga_state(0) & FPGA_STATE_PLATFORM;
if (legacy)
return in_le16((void *)LATCH3_BASE)
& CONFIG_SYS_FPGA_DONE(fpga);
else
return pca9698_get_value(0x22, fpga ? 9 : 8);
}