mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-13 15:03:58 +03:00
Merge commit 'remotes/wd/master'
Conflicts: MAKEALL With any luck, this is the last MAKEALL merge conflict!
This commit is contained in:
49
cpu/arm926ejs/davinci/Makefile
Normal file
49
cpu/arm926ejs/davinci/Makefile
Normal file
@@ -0,0 +1,49 @@
|
||||
#
|
||||
# (C) Copyright 2000-2006
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
|
||||
#
|
||||
# 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 $(TOPDIR)/config.mk
|
||||
|
||||
LIB = $(obj)lib$(SOC).a
|
||||
|
||||
COBJS = timer.o ether.o lxt972.o dp83848.o i2c.o nand.o
|
||||
SOBJS = lowlevel_init.o reset.o
|
||||
|
||||
SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
|
||||
OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS))
|
||||
START := $(addprefix $(obj),$(START))
|
||||
|
||||
all: $(obj).depend $(LIB)
|
||||
|
||||
$(LIB): $(OBJS)
|
||||
$(AR) $(ARFLAGS) $@ $(OBJS)
|
||||
|
||||
#########################################################################
|
||||
|
||||
# defines $(obj).depend target
|
||||
include $(SRCTREE)/rules.mk
|
||||
|
||||
sinclude $(obj).depend
|
||||
|
||||
#########################################################################
|
||||
156
cpu/arm926ejs/davinci/dp83848.c
Normal file
156
cpu/arm926ejs/davinci/dp83848.c
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* National Semiconductor DP83848 PHY Driver for TI DaVinci
|
||||
* (TMS320DM644x) based boards.
|
||||
*
|
||||
* Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
|
||||
*
|
||||
* --------------------------------------------------------
|
||||
*
|
||||
* 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 <net.h>
|
||||
#include <dp83848.h>
|
||||
#include <asm/arch/emac_defs.h>
|
||||
|
||||
#ifdef CONFIG_DRIVER_TI_EMAC
|
||||
|
||||
#ifdef CONFIG_CMD_NET
|
||||
|
||||
int dp83848_is_phy_connected(int phy_addr)
|
||||
{
|
||||
u_int16_t id1, id2;
|
||||
|
||||
if (!dm644x_eth_phy_read(phy_addr, DP83848_PHYID1_REG, &id1))
|
||||
return(0);
|
||||
if (!dm644x_eth_phy_read(phy_addr, DP83848_PHYID2_REG, &id2))
|
||||
return(0);
|
||||
|
||||
if ((id1 == DP83848_PHYID1_OUI) && (id2 == DP83848_PHYID2_OUI))
|
||||
return(1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int dp83848_get_link_speed(int phy_addr)
|
||||
{
|
||||
u_int16_t tmp;
|
||||
volatile emac_regs* emac = (emac_regs *)EMAC_BASE_ADDR;
|
||||
|
||||
if (!dm644x_eth_phy_read(phy_addr, DP83848_STAT_REG, &tmp))
|
||||
return(0);
|
||||
|
||||
if (!(tmp & DP83848_LINK_STATUS)) /* link up? */
|
||||
return(0);
|
||||
|
||||
if (!dm644x_eth_phy_read(phy_addr, DP83848_PHY_STAT_REG, &tmp))
|
||||
return(0);
|
||||
|
||||
/* Speed doesn't matter, there is no setting for it in EMAC... */
|
||||
if (tmp & DP83848_SPEED) {
|
||||
if (tmp & DP83848_DUPLEX) {
|
||||
/* set DM644x EMAC for Full Duplex */
|
||||
emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE;
|
||||
} else {
|
||||
/*set DM644x EMAC for Half Duplex */
|
||||
emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE;
|
||||
}
|
||||
|
||||
return(1);
|
||||
} else {
|
||||
if (tmp & DP83848_DUPLEX) {
|
||||
/* set DM644x EMAC for Full Duplex */
|
||||
emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE;
|
||||
} else {
|
||||
/*set DM644x EMAC for Half Duplex */
|
||||
emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE;
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int dp83848_init_phy(int phy_addr)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
if (!dp83848_get_link_speed(phy_addr)) {
|
||||
/* Try another time */
|
||||
udelay(100000);
|
||||
ret = dp83848_get_link_speed(phy_addr);
|
||||
}
|
||||
|
||||
/* Disable PHY Interrupts */
|
||||
dm644x_eth_phy_write(phy_addr, DP83848_PHY_INTR_CTRL_REG, 0);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
int dp83848_auto_negotiate(int phy_addr)
|
||||
{
|
||||
u_int16_t tmp;
|
||||
|
||||
|
||||
if (!dm644x_eth_phy_read(phy_addr, DP83848_CTL_REG, &tmp))
|
||||
return(0);
|
||||
|
||||
/* Restart Auto_negotiation */
|
||||
tmp &= ~DP83848_AUTONEG; /* remove autonegotiation enable */
|
||||
tmp |= DP83848_ISOLATE; /* Electrically isolate PHY */
|
||||
dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp);
|
||||
|
||||
/* Set the Auto_negotiation Advertisement Register
|
||||
* MII advertising for Next page, 100BaseTxFD and HD,
|
||||
* 10BaseTFD and HD, IEEE 802.3
|
||||
*/
|
||||
tmp = DP83848_NP | DP83848_TX_FDX | DP83848_TX_HDX |
|
||||
DP83848_10_FDX | DP83848_10_HDX | DP83848_AN_IEEE_802_3;
|
||||
dm644x_eth_phy_write(phy_addr, DP83848_ANA_REG, tmp);
|
||||
|
||||
|
||||
/* Read Control Register */
|
||||
if (!dm644x_eth_phy_read(phy_addr, DP83848_CTL_REG, &tmp))
|
||||
return(0);
|
||||
|
||||
tmp |= DP83848_SPEED_SELECT | DP83848_AUTONEG | DP83848_DUPLEX_MODE;
|
||||
dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp);
|
||||
|
||||
/* Restart Auto_negotiation */
|
||||
tmp |= DP83848_RESTART_AUTONEG;
|
||||
dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp);
|
||||
|
||||
/*check AutoNegotiate complete */
|
||||
udelay(10000);
|
||||
if (!dm644x_eth_phy_read(phy_addr, DP83848_STAT_REG, &tmp))
|
||||
return(0);
|
||||
|
||||
if (!(tmp & DP83848_AUTONEG_COMP))
|
||||
return(0);
|
||||
|
||||
return (dp83848_get_link_speed(phy_addr));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CMD_NET */
|
||||
|
||||
#endif /* CONFIG_DRIVER_ETHER */
|
||||
650
cpu/arm926ejs/davinci/ether.c
Normal file
650
cpu/arm926ejs/davinci/ether.c
Normal file
@@ -0,0 +1,650 @@
|
||||
/*
|
||||
* Ethernet driver for TI TMS320DM644x (DaVinci) chips.
|
||||
*
|
||||
* Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
|
||||
*
|
||||
* Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright
|
||||
* follows:
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* dm644x_emac.c
|
||||
*
|
||||
* TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM
|
||||
*
|
||||
* Copyright (C) 2005 Texas Instruments.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* ----------------------------------------------------------------------------
|
||||
|
||||
* Modifications:
|
||||
* ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot.
|
||||
* ver 1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors
|
||||
*
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <net.h>
|
||||
#include <miiphy.h>
|
||||
#include <asm/arch/emac_defs.h>
|
||||
|
||||
#ifdef CONFIG_DRIVER_TI_EMAC
|
||||
|
||||
#ifdef CONFIG_CMD_NET
|
||||
|
||||
unsigned int emac_dbg = 0;
|
||||
#define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args)
|
||||
|
||||
/* Internal static functions */
|
||||
static int dm644x_eth_hw_init (void);
|
||||
static int dm644x_eth_open (void);
|
||||
static int dm644x_eth_close (void);
|
||||
static int dm644x_eth_send_packet (volatile void *packet, int length);
|
||||
static int dm644x_eth_rcv_packet (void);
|
||||
static void dm644x_eth_mdio_enable(void);
|
||||
|
||||
static int gen_init_phy(int phy_addr);
|
||||
static int gen_is_phy_connected(int phy_addr);
|
||||
static int gen_get_link_speed(int phy_addr);
|
||||
static int gen_auto_negotiate(int phy_addr);
|
||||
|
||||
/* Wrappers exported to the U-Boot proper */
|
||||
int eth_hw_init(void)
|
||||
{
|
||||
return(dm644x_eth_hw_init());
|
||||
}
|
||||
|
||||
int eth_init(bd_t * bd)
|
||||
{
|
||||
return(dm644x_eth_open());
|
||||
}
|
||||
|
||||
void eth_halt(void)
|
||||
{
|
||||
dm644x_eth_close();
|
||||
}
|
||||
|
||||
int eth_send(volatile void *packet, int length)
|
||||
{
|
||||
return(dm644x_eth_send_packet(packet, length));
|
||||
}
|
||||
|
||||
int eth_rx(void)
|
||||
{
|
||||
return(dm644x_eth_rcv_packet());
|
||||
}
|
||||
|
||||
void eth_mdio_enable(void)
|
||||
{
|
||||
dm644x_eth_mdio_enable();
|
||||
}
|
||||
/* End of wrappers */
|
||||
|
||||
|
||||
static u_int8_t dm644x_eth_mac_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
/*
|
||||
* This function must be called before emac_open() if you want to override
|
||||
* the default mac address.
|
||||
*/
|
||||
void dm644x_eth_set_mac_addr(const u_int8_t *addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof (dm644x_eth_mac_addr); i++) {
|
||||
dm644x_eth_mac_addr[i] = addr[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* EMAC Addresses */
|
||||
static volatile emac_regs *adap_emac = (emac_regs *)EMAC_BASE_ADDR;
|
||||
static volatile ewrap_regs *adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR;
|
||||
static volatile mdio_regs *adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR;
|
||||
|
||||
/* EMAC descriptors */
|
||||
static volatile emac_desc *emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE);
|
||||
static volatile emac_desc *emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE);
|
||||
static volatile emac_desc *emac_rx_active_head = 0;
|
||||
static volatile emac_desc *emac_rx_active_tail = 0;
|
||||
static int emac_rx_queue_active = 0;
|
||||
|
||||
/* Receive packet buffers */
|
||||
static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)];
|
||||
|
||||
/* PHY address for a discovered PHY (0xff - not found) */
|
||||
static volatile u_int8_t active_phy_addr = 0xff;
|
||||
|
||||
phy_t phy;
|
||||
|
||||
static void dm644x_eth_mdio_enable(void)
|
||||
{
|
||||
u_int32_t clkdiv;
|
||||
|
||||
clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
|
||||
|
||||
adap_mdio->CONTROL = (clkdiv & 0xff) |
|
||||
MDIO_CONTROL_ENABLE |
|
||||
MDIO_CONTROL_FAULT |
|
||||
MDIO_CONTROL_FAULT_ENABLE;
|
||||
|
||||
while (adap_mdio->CONTROL & MDIO_CONTROL_IDLE) {;}
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to find an active connected PHY. Returns 1 if address if found.
|
||||
* If no active PHY (or more than one PHY) found returns 0.
|
||||
* Sets active_phy_addr variable.
|
||||
*/
|
||||
static int dm644x_eth_phy_detect(void)
|
||||
{
|
||||
u_int32_t phy_act_state;
|
||||
int i;
|
||||
|
||||
active_phy_addr = 0xff;
|
||||
|
||||
if ((phy_act_state = adap_mdio->ALIVE) == 0)
|
||||
return(0); /* No active PHYs */
|
||||
|
||||
debug_emac("dm644x_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state);
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (phy_act_state & (1 << i)) {
|
||||
if (phy_act_state & ~(1 << i))
|
||||
return(0); /* More than one PHY */
|
||||
else {
|
||||
active_phy_addr = i;
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(0); /* Just to make GCC happy */
|
||||
}
|
||||
|
||||
|
||||
/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */
|
||||
int dm644x_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;}
|
||||
|
||||
adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO |
|
||||
MDIO_USERACCESS0_WRITE_READ |
|
||||
((reg_num & 0x1f) << 21) |
|
||||
((phy_addr & 0x1f) << 16);
|
||||
|
||||
/* Wait for command to complete */
|
||||
while ((tmp = adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) {;}
|
||||
|
||||
if (tmp & MDIO_USERACCESS0_ACK) {
|
||||
*data = tmp & 0xffff;
|
||||
return(1);
|
||||
}
|
||||
|
||||
*data = -1;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */
|
||||
int dm644x_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data)
|
||||
{
|
||||
|
||||
while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;}
|
||||
|
||||
adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO |
|
||||
MDIO_USERACCESS0_WRITE_WRITE |
|
||||
((reg_num & 0x1f) << 21) |
|
||||
((phy_addr & 0x1f) << 16) |
|
||||
(data & 0xffff);
|
||||
|
||||
/* Wait for command to complete */
|
||||
while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* PHY functions for a generic PHY */
|
||||
static int gen_init_phy(int phy_addr)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
if (gen_get_link_speed(phy_addr)) {
|
||||
/* Try another time */
|
||||
ret = gen_get_link_speed(phy_addr);
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static int gen_is_phy_connected(int phy_addr)
|
||||
{
|
||||
u_int16_t dummy;
|
||||
|
||||
return(dm644x_eth_phy_read(phy_addr, PHY_PHYIDR1, &dummy));
|
||||
}
|
||||
|
||||
static int gen_get_link_speed(int phy_addr)
|
||||
{
|
||||
u_int16_t tmp;
|
||||
|
||||
if (dm644x_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) && (tmp & 0x04))
|
||||
return(1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int gen_auto_negotiate(int phy_addr)
|
||||
{
|
||||
u_int16_t tmp;
|
||||
|
||||
if (!dm644x_eth_phy_read(phy_addr, PHY_BMCR, &tmp))
|
||||
return(0);
|
||||
|
||||
/* Restart Auto_negotiation */
|
||||
tmp |= PHY_BMCR_AUTON;
|
||||
dm644x_eth_phy_write(phy_addr, PHY_BMCR, tmp);
|
||||
|
||||
/*check AutoNegotiate complete */
|
||||
udelay (10000);
|
||||
if (!dm644x_eth_phy_read(phy_addr, PHY_BMSR, &tmp))
|
||||
return(0);
|
||||
|
||||
if (!(tmp & PHY_BMSR_AUTN_COMP))
|
||||
return(0);
|
||||
|
||||
return(gen_get_link_speed(phy_addr));
|
||||
}
|
||||
/* End of generic PHY functions */
|
||||
|
||||
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
||||
static int dm644x_mii_phy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value)
|
||||
{
|
||||
return(dm644x_eth_phy_read(addr, reg, value) ? 0 : 1);
|
||||
}
|
||||
|
||||
static int dm644x_mii_phy_write(char *devname, unsigned char addr, unsigned char reg, unsigned short value)
|
||||
{
|
||||
return(dm644x_eth_phy_write(addr, reg, value) ? 0 : 1);
|
||||
}
|
||||
|
||||
int dm644x_eth_miiphy_initialize(bd_t *bis)
|
||||
{
|
||||
miiphy_register(phy.name, dm644x_mii_phy_read, dm644x_mii_phy_write);
|
||||
|
||||
return(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This function initializes the emac hardware. It does NOT initialize
|
||||
* EMAC modules power or pin multiplexors, that is done by board_init()
|
||||
* much earlier in bootup process. Returns 1 on success, 0 otherwise.
|
||||
*/
|
||||
static int dm644x_eth_hw_init(void)
|
||||
{
|
||||
u_int32_t phy_id;
|
||||
u_int16_t tmp;
|
||||
int i;
|
||||
|
||||
dm644x_eth_mdio_enable();
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (adap_mdio->ALIVE)
|
||||
break;
|
||||
udelay(10);
|
||||
}
|
||||
|
||||
if (i >= 256) {
|
||||
printf("No ETH PHY detected!!!\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Find if a PHY is connected and get it's address */
|
||||
if (!dm644x_eth_phy_detect())
|
||||
return(0);
|
||||
|
||||
/* Get PHY ID and initialize phy_ops for a detected PHY */
|
||||
if (!dm644x_eth_phy_read(active_phy_addr, PHY_PHYIDR1, &tmp)) {
|
||||
active_phy_addr = 0xff;
|
||||
return(0);
|
||||
}
|
||||
|
||||
phy_id = (tmp << 16) & 0xffff0000;
|
||||
|
||||
if (!dm644x_eth_phy_read(active_phy_addr, PHY_PHYIDR2, &tmp)) {
|
||||
active_phy_addr = 0xff;
|
||||
return(0);
|
||||
}
|
||||
|
||||
phy_id |= tmp & 0x0000ffff;
|
||||
|
||||
switch (phy_id) {
|
||||
case PHY_LXT972:
|
||||
sprintf(phy.name, "LXT972 @ 0x%02x", active_phy_addr);
|
||||
phy.init = lxt972_init_phy;
|
||||
phy.is_phy_connected = lxt972_is_phy_connected;
|
||||
phy.get_link_speed = lxt972_get_link_speed;
|
||||
phy.auto_negotiate = lxt972_auto_negotiate;
|
||||
break;
|
||||
case PHY_DP83848:
|
||||
sprintf(phy.name, "DP83848 @ 0x%02x", active_phy_addr);
|
||||
phy.init = dp83848_init_phy;
|
||||
phy.is_phy_connected = dp83848_is_phy_connected;
|
||||
phy.get_link_speed = dp83848_get_link_speed;
|
||||
phy.auto_negotiate = dp83848_auto_negotiate;
|
||||
break;
|
||||
default:
|
||||
sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr);
|
||||
phy.init = gen_init_phy;
|
||||
phy.is_phy_connected = gen_is_phy_connected;
|
||||
phy.get_link_speed = gen_get_link_speed;
|
||||
phy.auto_negotiate = gen_auto_negotiate;
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
/* Eth device open */
|
||||
static int dm644x_eth_open(void)
|
||||
{
|
||||
dv_reg_p addr;
|
||||
u_int32_t clkdiv, cnt;
|
||||
volatile emac_desc *rx_desc;
|
||||
|
||||
debug_emac("+ emac_open\n");
|
||||
|
||||
/* Reset EMAC module and disable interrupts in wrapper */
|
||||
adap_emac->SOFTRESET = 1;
|
||||
while (adap_emac->SOFTRESET != 0) {;}
|
||||
adap_ewrap->EWCTL = 0;
|
||||
for (cnt = 0; cnt < 5; cnt++) {
|
||||
clkdiv = adap_ewrap->EWCTL;
|
||||
}
|
||||
|
||||
rx_desc = emac_rx_desc;
|
||||
|
||||
adap_emac->TXCONTROL = 0x01;
|
||||
adap_emac->RXCONTROL = 0x01;
|
||||
|
||||
/* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast receive) */
|
||||
/* Using channel 0 only - other channels are disabled */
|
||||
adap_emac->MACINDEX = 0;
|
||||
adap_emac->MACADDRHI =
|
||||
(dm644x_eth_mac_addr[3] << 24) |
|
||||
(dm644x_eth_mac_addr[2] << 16) |
|
||||
(dm644x_eth_mac_addr[1] << 8) |
|
||||
(dm644x_eth_mac_addr[0]);
|
||||
adap_emac->MACADDRLO =
|
||||
(dm644x_eth_mac_addr[5] << 8) |
|
||||
(dm644x_eth_mac_addr[4]);
|
||||
|
||||
adap_emac->MACHASH1 = 0;
|
||||
adap_emac->MACHASH2 = 0;
|
||||
|
||||
/* Set source MAC address - REQUIRED */
|
||||
adap_emac->MACSRCADDRHI =
|
||||
(dm644x_eth_mac_addr[3] << 24) |
|
||||
(dm644x_eth_mac_addr[2] << 16) |
|
||||
(dm644x_eth_mac_addr[1] << 8) |
|
||||
(dm644x_eth_mac_addr[0]);
|
||||
adap_emac->MACSRCADDRLO =
|
||||
(dm644x_eth_mac_addr[4] << 8) |
|
||||
(dm644x_eth_mac_addr[5]);
|
||||
|
||||
/* Set DMA 8 TX / 8 RX Head pointers to 0 */
|
||||
addr = &adap_emac->TX0HDP;
|
||||
for(cnt = 0; cnt < 16; cnt++)
|
||||
*addr++ = 0;
|
||||
|
||||
addr = &adap_emac->RX0HDP;
|
||||
for(cnt = 0; cnt < 16; cnt++)
|
||||
*addr++ = 0;
|
||||
|
||||
/* Clear Statistics (do this before setting MacControl register) */
|
||||
addr = &adap_emac->RXGOODFRAMES;
|
||||
for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
|
||||
*addr++ = 0;
|
||||
|
||||
/* No multicast addressing */
|
||||
adap_emac->MACHASH1 = 0;
|
||||
adap_emac->MACHASH2 = 0;
|
||||
|
||||
/* Create RX queue and set receive process in place */
|
||||
emac_rx_active_head = emac_rx_desc;
|
||||
for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
|
||||
rx_desc->next = (u_int32_t)(rx_desc + 1);
|
||||
rx_desc->buffer = &emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)];
|
||||
rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
|
||||
rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
|
||||
rx_desc++;
|
||||
}
|
||||
|
||||
/* Set the last descriptor's "next" parameter to 0 to end the RX desc list */
|
||||
rx_desc--;
|
||||
rx_desc->next = 0;
|
||||
emac_rx_active_tail = rx_desc;
|
||||
emac_rx_queue_active = 1;
|
||||
|
||||
/* Enable TX/RX */
|
||||
adap_emac->RXMAXLEN = EMAC_MAX_ETHERNET_PKT_SIZE;
|
||||
adap_emac->RXBUFFEROFFSET = 0;
|
||||
|
||||
/* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */
|
||||
adap_emac->RXMBPENABLE = EMAC_RXMBPENABLE_RXBROADEN;
|
||||
|
||||
/* Enable ch 0 only */
|
||||
adap_emac->RXUNICASTSET = 0x01;
|
||||
|
||||
/* Enable MII interface and Full duplex mode */
|
||||
adap_emac->MACCONTROL = (EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE);
|
||||
|
||||
/* Init MDIO & get link state */
|
||||
clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
|
||||
adap_mdio->CONTROL = ((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT);
|
||||
|
||||
if (!phy.get_link_speed(active_phy_addr))
|
||||
return(0);
|
||||
|
||||
/* Start receive process */
|
||||
adap_emac->RX0HDP = (u_int32_t)emac_rx_desc;
|
||||
|
||||
debug_emac("- emac_open\n");
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* EMAC Channel Teardown */
|
||||
static void dm644x_eth_ch_teardown(int ch)
|
||||
{
|
||||
dv_reg dly = 0xff;
|
||||
dv_reg cnt;
|
||||
|
||||
debug_emac("+ emac_ch_teardown\n");
|
||||
|
||||
if (ch == EMAC_CH_TX) {
|
||||
/* Init TX channel teardown */
|
||||
adap_emac->TXTEARDOWN = 1;
|
||||
for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->TX0CP) {
|
||||
/* Wait here for Tx teardown completion interrupt to occur
|
||||
* Note: A task delay can be called here to pend rather than
|
||||
* occupying CPU cycles - anyway it has been found that teardown
|
||||
* takes very few cpu cycles and does not affect functionality */
|
||||
dly--;
|
||||
udelay(1);
|
||||
if (dly == 0)
|
||||
break;
|
||||
}
|
||||
adap_emac->TX0CP = cnt;
|
||||
adap_emac->TX0HDP = 0;
|
||||
} else {
|
||||
/* Init RX channel teardown */
|
||||
adap_emac->RXTEARDOWN = 1;
|
||||
for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->RX0CP) {
|
||||
/* Wait here for Rx teardown completion interrupt to occur
|
||||
* Note: A task delay can be called here to pend rather than
|
||||
* occupying CPU cycles - anyway it has been found that teardown
|
||||
* takes very few cpu cycles and does not affect functionality */
|
||||
dly--;
|
||||
udelay(1);
|
||||
if (dly == 0)
|
||||
break;
|
||||
}
|
||||
adap_emac->RX0CP = cnt;
|
||||
adap_emac->RX0HDP = 0;
|
||||
}
|
||||
|
||||
debug_emac("- emac_ch_teardown\n");
|
||||
}
|
||||
|
||||
/* Eth device close */
|
||||
static int dm644x_eth_close(void)
|
||||
{
|
||||
debug_emac("+ emac_close\n");
|
||||
|
||||
dm644x_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */
|
||||
dm644x_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */
|
||||
|
||||
/* Reset EMAC module and disable interrupts in wrapper */
|
||||
adap_emac->SOFTRESET = 1;
|
||||
adap_ewrap->EWCTL = 0;
|
||||
|
||||
debug_emac("- emac_close\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
static int tx_send_loop = 0;
|
||||
|
||||
/*
|
||||
* This function sends a single packet on the network and returns
|
||||
* positive number (number of bytes transmitted) or negative for error
|
||||
*/
|
||||
static int dm644x_eth_send_packet(volatile void *packet, int length)
|
||||
{
|
||||
int ret_status = -1;
|
||||
tx_send_loop = 0;
|
||||
|
||||
/* Return error if no link */
|
||||
if (!phy.get_link_speed(active_phy_addr))
|
||||
{
|
||||
printf("WARN: emac_send_packet: No link\n");
|
||||
return (ret_status);
|
||||
}
|
||||
|
||||
/* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
|
||||
if (length < EMAC_MIN_ETHERNET_PKT_SIZE)
|
||||
{
|
||||
length = EMAC_MIN_ETHERNET_PKT_SIZE;
|
||||
}
|
||||
|
||||
/* Populate the TX descriptor */
|
||||
emac_tx_desc->next = 0;
|
||||
emac_tx_desc->buffer = (u_int8_t *)packet;
|
||||
emac_tx_desc->buff_off_len = (length & 0xffff);
|
||||
emac_tx_desc->pkt_flag_len = ((length & 0xffff) |
|
||||
EMAC_CPPI_SOP_BIT |
|
||||
EMAC_CPPI_OWNERSHIP_BIT |
|
||||
EMAC_CPPI_EOP_BIT);
|
||||
/* Send the packet */
|
||||
adap_emac->TX0HDP = (unsigned int)emac_tx_desc;
|
||||
|
||||
/* Wait for packet to complete or link down */
|
||||
while (1) {
|
||||
if (!phy.get_link_speed(active_phy_addr)) {
|
||||
dm644x_eth_ch_teardown(EMAC_CH_TX);
|
||||
return (ret_status);
|
||||
}
|
||||
if (adap_emac->TXINTSTATRAW & 0x01) {
|
||||
ret_status = length;
|
||||
break;
|
||||
}
|
||||
tx_send_loop++;
|
||||
}
|
||||
|
||||
return(ret_status);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles receipt of a packet from the network
|
||||
*/
|
||||
static int dm644x_eth_rcv_packet(void)
|
||||
{
|
||||
volatile emac_desc *rx_curr_desc;
|
||||
volatile emac_desc *curr_desc;
|
||||
volatile emac_desc *tail_desc;
|
||||
int status, ret = -1;
|
||||
|
||||
rx_curr_desc = emac_rx_active_head;
|
||||
status = rx_curr_desc->pkt_flag_len;
|
||||
if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) {
|
||||
if (status & EMAC_CPPI_RX_ERROR_FRAME) {
|
||||
/* Error in packet - discard it and requeue desc */
|
||||
printf("WARN: emac_rcv_pkt: Error in packet\n");
|
||||
} else {
|
||||
NetReceive(rx_curr_desc->buffer, (rx_curr_desc->buff_off_len & 0xffff));
|
||||
ret = rx_curr_desc->buff_off_len & 0xffff;
|
||||
}
|
||||
|
||||
/* Ack received packet descriptor */
|
||||
adap_emac->RX0CP = (unsigned int)rx_curr_desc;
|
||||
curr_desc = rx_curr_desc;
|
||||
emac_rx_active_head = (volatile emac_desc *)rx_curr_desc->next;
|
||||
|
||||
if (status & EMAC_CPPI_EOQ_BIT) {
|
||||
if (emac_rx_active_head) {
|
||||
adap_emac->RX0HDP = (unsigned int)emac_rx_active_head;
|
||||
} else {
|
||||
emac_rx_queue_active = 0;
|
||||
printf("INFO:emac_rcv_packet: RX Queue not active\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Recycle RX descriptor */
|
||||
rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
|
||||
rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
|
||||
rx_curr_desc->next = 0;
|
||||
|
||||
if (emac_rx_active_head == 0) {
|
||||
printf("INFO: emac_rcv_pkt: active queue head = 0\n");
|
||||
emac_rx_active_head = curr_desc;
|
||||
emac_rx_active_tail = curr_desc;
|
||||
if (emac_rx_queue_active != 0) {
|
||||
adap_emac->RX0HDP = (unsigned int)emac_rx_active_head;
|
||||
printf("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
|
||||
emac_rx_queue_active = 1;
|
||||
}
|
||||
} else {
|
||||
tail_desc = emac_rx_active_tail;
|
||||
emac_rx_active_tail = curr_desc;
|
||||
tail_desc->next = (unsigned int)curr_desc;
|
||||
status = tail_desc->pkt_flag_len;
|
||||
if (status & EMAC_CPPI_EOQ_BIT) {
|
||||
adap_emac->RX0HDP = (unsigned int)curr_desc;
|
||||
status &= ~EMAC_CPPI_EOQ_BIT;
|
||||
tail_desc->pkt_flag_len = status;
|
||||
}
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CMD_NET */
|
||||
|
||||
#endif /* CONFIG_DRIVER_TI_EMAC */
|
||||
351
cpu/arm926ejs/davinci/i2c.c
Normal file
351
cpu/arm926ejs/davinci/i2c.c
Normal file
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* TI DaVinci (TMS320DM644x) I2C driver.
|
||||
*
|
||||
* Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
|
||||
*
|
||||
* --------------------------------------------------------
|
||||
*
|
||||
* 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>
|
||||
|
||||
#ifdef CONFIG_DRIVER_DAVINCI_I2C
|
||||
|
||||
#include <i2c.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/i2c_defs.h>
|
||||
|
||||
#define CHECK_NACK() \
|
||||
do {\
|
||||
if (tmp & (I2C_TIMEOUT | I2C_STAT_NACK)) {\
|
||||
REG(I2C_CON) = 0;\
|
||||
return(1);\
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
|
||||
static int wait_for_bus(void)
|
||||
{
|
||||
int stat, timeout;
|
||||
|
||||
REG(I2C_STAT) = 0xffff;
|
||||
|
||||
for (timeout = 0; timeout < 10; timeout++) {
|
||||
if (!((stat = REG(I2C_STAT)) & I2C_STAT_BB)) {
|
||||
REG(I2C_STAT) = 0xffff;
|
||||
return(0);
|
||||
}
|
||||
|
||||
REG(I2C_STAT) = stat;
|
||||
udelay(50000);
|
||||
}
|
||||
|
||||
REG(I2C_STAT) = 0xffff;
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
static int poll_i2c_irq(int mask)
|
||||
{
|
||||
int stat, timeout;
|
||||
|
||||
for (timeout = 0; timeout < 10; timeout++) {
|
||||
udelay(1000);
|
||||
stat = REG(I2C_STAT);
|
||||
if (stat & mask) {
|
||||
return(stat);
|
||||
}
|
||||
}
|
||||
|
||||
REG(I2C_STAT) = 0xffff;
|
||||
return(stat | I2C_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
void flush_rx(void)
|
||||
{
|
||||
int dummy;
|
||||
|
||||
while (1) {
|
||||
if (!(REG(I2C_STAT) & I2C_STAT_RRDY))
|
||||
break;
|
||||
|
||||
dummy = REG(I2C_DRR);
|
||||
REG(I2C_STAT) = I2C_STAT_RRDY;
|
||||
udelay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void i2c_init(int speed, int slaveadd)
|
||||
{
|
||||
u_int32_t div, psc;
|
||||
|
||||
if (REG(I2C_CON) & I2C_CON_EN) {
|
||||
REG(I2C_CON) = 0;
|
||||
udelay (50000);
|
||||
}
|
||||
|
||||
psc = 2;
|
||||
div = (CFG_HZ_CLOCK / ((psc + 1) * speed)) - 10; /* SCLL + SCLH */
|
||||
REG(I2C_PSC) = psc; /* 27MHz / (2 + 1) = 9MHz */
|
||||
REG(I2C_SCLL) = (div * 50) / 100; /* 50% Duty */
|
||||
REG(I2C_SCLH) = div - REG(I2C_SCLL);
|
||||
|
||||
REG(I2C_OA) = slaveadd;
|
||||
REG(I2C_CNT) = 0;
|
||||
|
||||
/* Interrupts must be enabled or I2C module won't work */
|
||||
REG(I2C_IE) = I2C_IE_SCD_IE | I2C_IE_XRDY_IE |
|
||||
I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE;
|
||||
|
||||
/* Now enable I2C controller (get it out of reset) */
|
||||
REG(I2C_CON) = I2C_CON_EN;
|
||||
|
||||
udelay(1000);
|
||||
}
|
||||
|
||||
|
||||
int i2c_probe(u_int8_t chip)
|
||||
{
|
||||
int rc = 1;
|
||||
|
||||
if (chip == REG(I2C_OA)) {
|
||||
return(rc);
|
||||
}
|
||||
|
||||
REG(I2C_CON) = 0;
|
||||
if (wait_for_bus()) {return(1);}
|
||||
|
||||
/* try to read one byte from current (or only) address */
|
||||
REG(I2C_CNT) = 1;
|
||||
REG(I2C_SA) = chip;
|
||||
REG(I2C_CON) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP);
|
||||
udelay (50000);
|
||||
|
||||
if (!(REG(I2C_STAT) & I2C_STAT_NACK)) {
|
||||
rc = 0;
|
||||
flush_rx();
|
||||
REG(I2C_STAT) = 0xffff;
|
||||
} else {
|
||||
REG(I2C_STAT) = 0xffff;
|
||||
REG(I2C_CON) |= I2C_CON_STP;
|
||||
udelay(20000);
|
||||
if (wait_for_bus()) {return(1);}
|
||||
}
|
||||
|
||||
flush_rx();
|
||||
REG(I2C_STAT) = 0xffff;
|
||||
REG(I2C_CNT) = 0;
|
||||
return(rc);
|
||||
}
|
||||
|
||||
|
||||
int i2c_read(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len)
|
||||
{
|
||||
u_int32_t tmp;
|
||||
int i;
|
||||
|
||||
if ((alen < 0) || (alen > 2)) {
|
||||
printf("%s(): bogus address length %x\n", __FUNCTION__, alen);
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (wait_for_bus()) {return(1);}
|
||||
|
||||
if (alen != 0) {
|
||||
/* Start address phase */
|
||||
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX;
|
||||
REG(I2C_CNT) = alen;
|
||||
REG(I2C_SA) = chip;
|
||||
REG(I2C_CON) = tmp;
|
||||
|
||||
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
|
||||
|
||||
CHECK_NACK();
|
||||
|
||||
switch (alen) {
|
||||
case 2:
|
||||
/* Send address MSByte */
|
||||
if (tmp & I2C_STAT_XRDY) {
|
||||
REG(I2C_DXR) = (addr >> 8) & 0xff;
|
||||
} else {
|
||||
REG(I2C_CON) = 0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
|
||||
|
||||
CHECK_NACK();
|
||||
/* No break, fall through */
|
||||
case 1:
|
||||
/* Send address LSByte */
|
||||
if (tmp & I2C_STAT_XRDY) {
|
||||
REG(I2C_DXR) = addr & 0xff;
|
||||
} else {
|
||||
REG(I2C_CON) = 0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK | I2C_STAT_ARDY);
|
||||
|
||||
CHECK_NACK();
|
||||
|
||||
if (!(tmp & I2C_STAT_ARDY)) {
|
||||
REG(I2C_CON) = 0;
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Address phase is over, now read 'len' bytes and stop */
|
||||
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
|
||||
REG(I2C_CNT) = len & 0xffff;
|
||||
REG(I2C_SA) = chip;
|
||||
REG(I2C_CON) = tmp;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
tmp = poll_i2c_irq(I2C_STAT_RRDY | I2C_STAT_NACK | I2C_STAT_ROVR);
|
||||
|
||||
CHECK_NACK();
|
||||
|
||||
if (tmp & I2C_STAT_RRDY) {
|
||||
buf[i] = REG(I2C_DRR);
|
||||
} else {
|
||||
REG(I2C_CON) = 0;
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK);
|
||||
|
||||
CHECK_NACK();
|
||||
|
||||
if (!(tmp & I2C_STAT_SCD)) {
|
||||
REG(I2C_CON) = 0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
flush_rx();
|
||||
REG(I2C_STAT) = 0xffff;
|
||||
REG(I2C_CNT) = 0;
|
||||
REG(I2C_CON) = 0;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int i2c_write(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len)
|
||||
{
|
||||
u_int32_t tmp;
|
||||
int i;
|
||||
|
||||
if ((alen < 0) || (alen > 2)) {
|
||||
printf("%s(): bogus address length %x\n", __FUNCTION__, alen);
|
||||
return(1);
|
||||
}
|
||||
if (len < 0) {
|
||||
printf("%s(): bogus length %x\n", __FUNCTION__, len);
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (wait_for_bus()) {return(1);}
|
||||
|
||||
/* Start address phase */
|
||||
tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP;
|
||||
REG(I2C_CNT) = (alen == 0) ? len & 0xffff : (len & 0xffff) + alen;
|
||||
REG(I2C_SA) = chip;
|
||||
REG(I2C_CON) = tmp;
|
||||
|
||||
switch (alen) {
|
||||
case 2:
|
||||
/* Send address MSByte */
|
||||
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
|
||||
|
||||
CHECK_NACK();
|
||||
|
||||
if (tmp & I2C_STAT_XRDY) {
|
||||
REG(I2C_DXR) = (addr >> 8) & 0xff;
|
||||
} else {
|
||||
REG(I2C_CON) = 0;
|
||||
return(1);
|
||||
}
|
||||
/* No break, fall through */
|
||||
case 1:
|
||||
/* Send address LSByte */
|
||||
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
|
||||
|
||||
CHECK_NACK();
|
||||
|
||||
if (tmp & I2C_STAT_XRDY) {
|
||||
REG(I2C_DXR) = addr & 0xff;
|
||||
} else {
|
||||
REG(I2C_CON) = 0;
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
|
||||
|
||||
CHECK_NACK();
|
||||
|
||||
if (tmp & I2C_STAT_XRDY) {
|
||||
REG(I2C_DXR) = buf[i];
|
||||
} else {
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK);
|
||||
|
||||
CHECK_NACK();
|
||||
|
||||
if (!(tmp & I2C_STAT_SCD)) {
|
||||
REG(I2C_CON) = 0;
|
||||
return(1);
|
||||
}
|
||||
|
||||
flush_rx();
|
||||
REG(I2C_STAT) = 0xffff;
|
||||
REG(I2C_CNT) = 0;
|
||||
REG(I2C_CON) = 0;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
u_int8_t i2c_reg_read(u_int8_t chip, u_int8_t reg)
|
||||
{
|
||||
u_int8_t tmp;
|
||||
|
||||
i2c_read(chip, reg, 1, &tmp, 1);
|
||||
return(tmp);
|
||||
}
|
||||
|
||||
|
||||
void i2c_reg_write(u_int8_t chip, u_int8_t reg, u_int8_t val)
|
||||
{
|
||||
u_int8_t tmp;
|
||||
|
||||
i2c_write(chip, reg, 1, &tmp, 1);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DRIVER_DAVINCI_I2C */
|
||||
707
cpu/arm926ejs/davinci/lowlevel_init.S
Normal file
707
cpu/arm926ejs/davinci/lowlevel_init.S
Normal file
@@ -0,0 +1,707 @@
|
||||
/*
|
||||
* Low-level board setup code for TI DaVinci SoC based boards.
|
||||
*
|
||||
* Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
|
||||
*
|
||||
* Partially based on TI sources, original copyrights follow:
|
||||
*/
|
||||
|
||||
/*
|
||||
* Board specific setup info
|
||||
*
|
||||
* (C) Copyright 2003
|
||||
* Texas Instruments, <www.ti.com>
|
||||
* Kshitij Gupta <Kshitij@ti.com>
|
||||
*
|
||||
* Modified for OMAP 1610 H2 board by Nishant Kamat, Jan 2004
|
||||
*
|
||||
* Modified for OMAP 5912 OSK board by Rishi Bhattacharya, Apr 2004
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* Modified for DV-EVM board by Rishi Bhattacharya, Apr 2005
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* Modified for DV-EVM board by Swaminathan S, Nov 2005
|
||||
* 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 <config.h>
|
||||
|
||||
.globl lowlevel_init
|
||||
lowlevel_init:
|
||||
|
||||
/*-------------------------------------------------------*
|
||||
* Mask all IRQs by setting all bits in the EINT default *
|
||||
*-------------------------------------------------------*/
|
||||
mov r1, $0
|
||||
ldr r0, =EINT_ENABLE0
|
||||
str r1, [r0]
|
||||
ldr r0, =EINT_ENABLE1
|
||||
str r1, [r0]
|
||||
|
||||
/*------------------------------------------------------*
|
||||
* Put the GEM in reset *
|
||||
*------------------------------------------------------*/
|
||||
|
||||
/* Put the GEM in reset */
|
||||
ldr r8, PSC_GEM_FLAG_CLEAR
|
||||
ldr r6, MDCTL_GEM
|
||||
ldr r7, [r6]
|
||||
and r7, r7, r8
|
||||
str r7, [r6]
|
||||
|
||||
/* Enable the Power Domain Transition Command */
|
||||
ldr r6, PTCMD
|
||||
ldr r7, [r6]
|
||||
orr r7, r7, $0x02
|
||||
str r7, [r6]
|
||||
|
||||
/* Check for Transition Complete(PTSTAT) */
|
||||
checkStatClkStopGem:
|
||||
ldr r6, PTSTAT
|
||||
ldr r7, [r6]
|
||||
ands r7, r7, $0x02
|
||||
bne checkStatClkStopGem
|
||||
|
||||
/* Check for GEM Reset Completion */
|
||||
checkGemStatClkStop:
|
||||
ldr r6, MDSTAT_GEM
|
||||
ldr r7, [r6]
|
||||
ands r7, r7, $0x100
|
||||
bne checkGemStatClkStop
|
||||
|
||||
/* Do this for enabling a WDT initiated reset this is a workaround
|
||||
for a chip bug. Not required under normal situations */
|
||||
ldr r6, P1394
|
||||
mov r10, $0
|
||||
str r10, [r6]
|
||||
|
||||
/*------------------------------------------------------*
|
||||
* Enable L1 & L2 Memories in Fast mode *
|
||||
*------------------------------------------------------*/
|
||||
ldr r6, DFT_ENABLE
|
||||
mov r10, $0x01
|
||||
str r10, [r6]
|
||||
|
||||
ldr r6, MMARG_BRF0
|
||||
ldr r10, MMARG_BRF0_VAL
|
||||
str r10, [r6]
|
||||
|
||||
ldr r6, DFT_ENABLE
|
||||
mov r10, $0
|
||||
str r10, [r6]
|
||||
|
||||
/*------------------------------------------------------*
|
||||
* DDR2 PLL Initialization *
|
||||
*------------------------------------------------------*/
|
||||
|
||||
/* Select the Clock Mode Depending on the Value written in the Boot Table by the run script */
|
||||
mov r10, $0
|
||||
ldr r6, PLL2_CTL
|
||||
ldr r7, PLL_CLKSRC_MASK
|
||||
ldr r8, [r6]
|
||||
and r8, r8, r7
|
||||
mov r9, r10, lsl $8
|
||||
orr r8, r8, r9
|
||||
str r8, [r6]
|
||||
|
||||
/* Select the PLLEN source */
|
||||
ldr r7, PLL_ENSRC_MASK
|
||||
and r8, r8, r7
|
||||
str r8, [r6]
|
||||
|
||||
/* Bypass the PLL */
|
||||
ldr r7, PLL_BYPASS_MASK
|
||||
and r8, r8, r7
|
||||
str r8, [r6]
|
||||
|
||||
/* Wait for few cycles to allow PLLEN Mux switch properly to bypass Clock */
|
||||
mov r10, $0x20
|
||||
WaitPPL2Loop:
|
||||
subs r10, r10, $1
|
||||
bne WaitPPL2Loop
|
||||
|
||||
/* Reset the PLL */
|
||||
ldr r7, PLL_RESET_MASK
|
||||
and r8, r8, r7
|
||||
str r8, [r6]
|
||||
|
||||
/* Power up the PLL */
|
||||
ldr r7, PLL_PWRUP_MASK
|
||||
and r8, r8, r7
|
||||
str r8, [r6]
|
||||
|
||||
/* Enable the PLL from Disable Mode */
|
||||
ldr r7, PLL_DISABLE_ENABLE_MASK
|
||||
and r8, r8, r7
|
||||
str r8, [r6]
|
||||
|
||||
/* Program the PLL Multiplier */
|
||||
ldr r6, PLL2_PLLM
|
||||
mov r2, $0x17 /* 162 MHz */
|
||||
str r2, [r6]
|
||||
|
||||
/* Program the PLL2 Divisor Value */
|
||||
ldr r6, PLL2_DIV2
|
||||
mov r3, $0x01
|
||||
str r3, [r6]
|
||||
|
||||
/* Program the PLL2 Divisor Value */
|
||||
ldr r6, PLL2_DIV1
|
||||
mov r4, $0x0b /* 54 MHz */
|
||||
str r4, [r6]
|
||||
|
||||
/* PLL2 DIV2 MMR */
|
||||
ldr r8, PLL2_DIV_MASK
|
||||
ldr r6, PLL2_DIV2
|
||||
ldr r9, [r6]
|
||||
and r8, r8, r9
|
||||
mov r9, $0x01
|
||||
mov r9, r9, lsl $15
|
||||
orr r8, r8, r9
|
||||
str r8, [r6]
|
||||
|
||||
/* Program the GOSET bit to take new divider values */
|
||||
ldr r6, PLL2_PLLCMD
|
||||
ldr r7, [r6]
|
||||
orr r7, r7, $0x01
|
||||
str r7, [r6]
|
||||
|
||||
/* Wait for Done */
|
||||
ldr r6, PLL2_PLLSTAT
|
||||
doneLoop_0:
|
||||
ldr r7, [r6]
|
||||
ands r7, r7, $0x01
|
||||
bne doneLoop_0
|
||||
|
||||
/* PLL2 DIV1 MMR */
|
||||
ldr r8, PLL2_DIV_MASK
|
||||
ldr r6, PLL2_DIV1
|
||||
ldr r9, [r6]
|
||||
and r8, r8, r9
|
||||
mov r9, $0x01
|
||||
mov r9, r9, lsl $15
|
||||
orr r8, r8, r9
|
||||
str r8, [r6]
|
||||
|
||||
/* Program the GOSET bit to take new divider values */
|
||||
ldr r6, PLL2_PLLCMD
|
||||
ldr r7, [r6]
|
||||
orr r7, r7, $0x01
|
||||
str r7, [r6]
|
||||
|
||||
/* Wait for Done */
|
||||
ldr r6, PLL2_PLLSTAT
|
||||
doneLoop:
|
||||
ldr r7, [r6]
|
||||
ands r7, r7, $0x01
|
||||
bne doneLoop
|
||||
|
||||
/* Wait for PLL to Reset Properly */
|
||||
mov r10, $0x218
|
||||
ResetPPL2Loop:
|
||||
subs r10, r10, $1
|
||||
bne ResetPPL2Loop
|
||||
|
||||
/* Bring PLL out of Reset */
|
||||
ldr r6, PLL2_CTL
|
||||
ldr r8, [r6]
|
||||
orr r8, r8, $0x08
|
||||
str r8, [r6]
|
||||
|
||||
/* Wait for PLL to Lock */
|
||||
ldr r10, PLL_LOCK_COUNT
|
||||
PLL2Lock:
|
||||
subs r10, r10, $1
|
||||
bne PLL2Lock
|
||||
|
||||
/* Enable the PLL */
|
||||
ldr r6, PLL2_CTL
|
||||
ldr r8, [r6]
|
||||
orr r8, r8, $0x01
|
||||
str r8, [r6]
|
||||
|
||||
/*------------------------------------------------------*
|
||||
* Issue Soft Reset to DDR Module *
|
||||
*------------------------------------------------------*/
|
||||
|
||||
/* Shut down the DDR2 LPSC Module */
|
||||
ldr r8, PSC_FLAG_CLEAR
|
||||
ldr r6, MDCTL_DDR2
|
||||
ldr r7, [r6]
|
||||
and r7, r7, r8
|
||||
orr r7, r7, $0x03
|
||||
str r7, [r6]
|
||||
|
||||
/* Enable the Power Domain Transition Command */
|
||||
ldr r6, PTCMD
|
||||
ldr r7, [r6]
|
||||
orr r7, r7, $0x01
|
||||
str r7, [r6]
|
||||
|
||||
/* Check for Transition Complete(PTSTAT) */
|
||||
checkStatClkStop:
|
||||
ldr r6, PTSTAT
|
||||
ldr r7, [r6]
|
||||
ands r7, r7, $0x01
|
||||
bne checkStatClkStop
|
||||
|
||||
/* Check for DDR2 Controller Enable Completion */
|
||||
checkDDRStatClkStop:
|
||||
ldr r6, MDSTAT_DDR2
|
||||
ldr r7, [r6]
|
||||
and r7, r7, $0x1f
|
||||
cmp r7, $0x03
|
||||
bne checkDDRStatClkStop
|
||||
|
||||
/*------------------------------------------------------*
|
||||
* Program DDR2 MMRs for 162MHz Setting *
|
||||
*------------------------------------------------------*/
|
||||
|
||||
/* Program PHY Control Register */
|
||||
ldr r6, DDRCTL
|
||||
ldr r7, DDRCTL_VAL
|
||||
str r7, [r6]
|
||||
|
||||
/* Program SDRAM Bank Config Register */
|
||||
ldr r6, SDCFG
|
||||
ldr r7, SDCFG_VAL
|
||||
str r7, [r6]
|
||||
|
||||
/* Program SDRAM TIM-0 Config Register */
|
||||
ldr r6, SDTIM0
|
||||
ldr r7, SDTIM0_VAL_162MHz
|
||||
str r7, [r6]
|
||||
|
||||
/* Program SDRAM TIM-1 Config Register */
|
||||
ldr r6, SDTIM1
|
||||
ldr r7, SDTIM1_VAL_162MHz
|
||||
str r7, [r6]
|
||||
|
||||
/* Program the SDRAM Bank Config Control Register */
|
||||
ldr r10, MASK_VAL
|
||||
ldr r8, SDCFG
|
||||
ldr r9, SDCFG_VAL
|
||||
and r9, r9, r10
|
||||
str r9, [r8]
|
||||
|
||||
/* Program SDRAM SDREF Config Register */
|
||||
ldr r6, SDREF
|
||||
ldr r7, SDREF_VAL
|
||||
str r7, [r6]
|
||||
|
||||
/*------------------------------------------------------*
|
||||
* Issue Soft Reset to DDR Module *
|
||||
*------------------------------------------------------*/
|
||||
|
||||
/* Issue a Dummy DDR2 read/write */
|
||||
ldr r8, DDR2_START_ADDR
|
||||
ldr r7, DUMMY_VAL
|
||||
str r7, [r8]
|
||||
ldr r7, [r8]
|
||||
|
||||
/* Shut down the DDR2 LPSC Module */
|
||||
ldr r8, PSC_FLAG_CLEAR
|
||||
ldr r6, MDCTL_DDR2
|
||||
ldr r7, [r6]
|
||||
and r7, r7, r8
|
||||
orr r7, r7, $0x01
|
||||
str r7, [r6]
|
||||
|
||||
/* Enable the Power Domain Transition Command */
|
||||
ldr r6, PTCMD
|
||||
ldr r7, [r6]
|
||||
orr r7, r7, $0x01
|
||||
str r7, [r6]
|
||||
|
||||
/* Check for Transition Complete(PTSTAT) */
|
||||
checkStatClkStop2:
|
||||
ldr r6, PTSTAT
|
||||
ldr r7, [r6]
|
||||
ands r7, r7, $0x01
|
||||
bne checkStatClkStop2
|
||||
|
||||
/* Check for DDR2 Controller Enable Completion */
|
||||
checkDDRStatClkStop2:
|
||||
ldr r6, MDSTAT_DDR2
|
||||
ldr r7, [r6]
|
||||
and r7, r7, $0x1f
|
||||
cmp r7, $0x01
|
||||
bne checkDDRStatClkStop2
|
||||
|
||||
/*------------------------------------------------------*
|
||||
* Turn DDR2 Controller Clocks On *
|
||||
*------------------------------------------------------*/
|
||||
|
||||
/* Enable the DDR2 LPSC Module */
|
||||
ldr r6, MDCTL_DDR2
|
||||
ldr r7, [r6]
|
||||
orr r7, r7, $0x03
|
||||
str r7, [r6]
|
||||
|
||||
/* Enable the Power Domain Transition Command */
|
||||
ldr r6, PTCMD
|
||||
ldr r7, [r6]
|
||||
orr r7, r7, $0x01
|
||||
str r7, [r6]
|
||||
|
||||
/* Check for Transition Complete(PTSTAT) */
|
||||
checkStatClkEn2:
|
||||
ldr r6, PTSTAT
|
||||
ldr r7, [r6]
|
||||
ands r7, r7, $0x01
|
||||
bne checkStatClkEn2
|
||||
|
||||
/* Check for DDR2 Controller Enable Completion */
|
||||
checkDDRStatClkEn2:
|
||||
ldr r6, MDSTAT_DDR2
|
||||
ldr r7, [r6]
|
||||
and r7, r7, $0x1f
|
||||
cmp r7, $0x03
|
||||
bne checkDDRStatClkEn2
|
||||
|
||||
/* DDR Writes and Reads */
|
||||
ldr r6, CFGTEST
|
||||
mov r3, $0x01
|
||||
str r3, [r6]
|
||||
|
||||
/*------------------------------------------------------*
|
||||
* System PLL Initialization *
|
||||
*------------------------------------------------------*/
|
||||
|
||||
/* Select the Clock Mode Depending on the Value written in the Boot Table by the run script */
|
||||
mov r2, $0
|
||||
ldr r6, PLL1_CTL
|
||||
ldr r7, PLL_CLKSRC_MASK
|
||||
ldr r8, [r6]
|
||||
and r8, r8, r7
|
||||
mov r9, r2, lsl $8
|
||||
orr r8, r8, r9
|
||||
str r8, [r6]
|
||||
|
||||
/* Select the PLLEN source */
|
||||
ldr r7, PLL_ENSRC_MASK
|
||||
and r8, r8, r7
|
||||
str r8, [r6]
|
||||
|
||||
/* Bypass the PLL */
|
||||
ldr r7, PLL_BYPASS_MASK
|
||||
and r8, r8, r7
|
||||
str r8, [r6]
|
||||
|
||||
/* Wait for few cycles to allow PLLEN Mux switch properly to bypass Clock */
|
||||
mov r10, $0x20
|
||||
|
||||
WaitLoop:
|
||||
subs r10, r10, $1
|
||||
bne WaitLoop
|
||||
|
||||
/* Reset the PLL */
|
||||
ldr r7, PLL_RESET_MASK
|
||||
and r8, r8, r7
|
||||
str r8, [r6]
|
||||
|
||||
/* Disable the PLL */
|
||||
orr r8, r8, $0x10
|
||||
str r8, [r6]
|
||||
|
||||
/* Power up the PLL */
|
||||
ldr r7, PLL_PWRUP_MASK
|
||||
and r8, r8, r7
|
||||
str r8, [r6]
|
||||
|
||||
/* Enable the PLL from Disable Mode */
|
||||
ldr r7, PLL_DISABLE_ENABLE_MASK
|
||||
and r8, r8, r7
|
||||
str r8, [r6]
|
||||
|
||||
/* Program the PLL Multiplier */
|
||||
ldr r6, PLL1_PLLM
|
||||
mov r3, $0x15 /* For 594MHz */
|
||||
str r3, [r6]
|
||||
|
||||
/* Wait for PLL to Reset Properly */
|
||||
mov r10, $0xff
|
||||
|
||||
ResetLoop:
|
||||
subs r10, r10, $1
|
||||
bne ResetLoop
|
||||
|
||||
/* Bring PLL out of Reset */
|
||||
ldr r6, PLL1_CTL
|
||||
orr r8, r8, $0x08
|
||||
str r8, [r6]
|
||||
|
||||
/* Wait for PLL to Lock */
|
||||
ldr r10, PLL_LOCK_COUNT
|
||||
|
||||
PLL1Lock:
|
||||
subs r10, r10, $1
|
||||
bne PLL1Lock
|
||||
|
||||
/* Enable the PLL */
|
||||
orr r8, r8, $0x01
|
||||
str r8, [r6]
|
||||
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
/*------------------------------------------------------*
|
||||
* AEMIF configuration for NOR Flash (double check) *
|
||||
*------------------------------------------------------*/
|
||||
ldr r0, _PINMUX0
|
||||
ldr r1, _DEV_SETTING
|
||||
str r1, [r0]
|
||||
|
||||
ldr r0, WAITCFG
|
||||
ldr r1, WAITCFG_VAL
|
||||
ldr r2, [r0]
|
||||
orr r2, r2, r1
|
||||
str r2, [r0]
|
||||
|
||||
ldr r0, ACFG3
|
||||
ldr r1, ACFG3_VAL
|
||||
ldr r2, [r0]
|
||||
and r1, r2, r1
|
||||
str r1, [r0]
|
||||
|
||||
ldr r0, ACFG4
|
||||
ldr r1, ACFG4_VAL
|
||||
ldr r2, [r0]
|
||||
and r1, r2, r1
|
||||
str r1, [r0]
|
||||
|
||||
ldr r0, ACFG5
|
||||
ldr r1, ACFG5_VAL
|
||||
ldr r2, [r0]
|
||||
and r1, r2, r1
|
||||
str r1, [r0]
|
||||
|
||||
/*--------------------------------------*
|
||||
* VTP manual Calibration *
|
||||
*--------------------------------------*/
|
||||
ldr r0, VTPIOCR
|
||||
ldr r1, VTP_MMR0
|
||||
str r1, [r0]
|
||||
|
||||
ldr r0, VTPIOCR
|
||||
ldr r1, VTP_MMR1
|
||||
str r1, [r0]
|
||||
|
||||
/* Wait for 33 VTP CLK cycles. VRP operates at 27 MHz */
|
||||
ldr r10, VTP_LOCK_COUNT
|
||||
VTPLock:
|
||||
subs r10, r10, $1
|
||||
bne VTPLock
|
||||
|
||||
ldr r6, DFT_ENABLE
|
||||
mov r10, $0x01
|
||||
str r10, [r6]
|
||||
|
||||
ldr r6, DDRVTPR
|
||||
ldr r7, [r6]
|
||||
and r7, r7, $0x1f
|
||||
and r8, r7, $0x3e0
|
||||
orr r8, r7, r8
|
||||
ldr r7, VTP_RECAL
|
||||
orr r8, r7, r8
|
||||
ldr r7, VTP_EN
|
||||
orr r8, r7, r8
|
||||
str r8, [r0]
|
||||
|
||||
|
||||
/* Wait for 33 VTP CLK cycles. VRP operates at 27 MHz */
|
||||
ldr r10, VTP_LOCK_COUNT
|
||||
VTP1Lock:
|
||||
subs r10, r10, $1
|
||||
bne VTP1Lock
|
||||
|
||||
ldr r1, [r0]
|
||||
ldr r2, VTP_MASK
|
||||
and r2, r1, r2
|
||||
str r2, [r0]
|
||||
|
||||
ldr r6, DFT_ENABLE
|
||||
mov r10, $0
|
||||
str r10, [r6]
|
||||
|
||||
/*
|
||||
* Call board-specific lowlevel init.
|
||||
* That MUST be present and THAT returns
|
||||
* back to arch calling code with "mov pc, lr."
|
||||
*/
|
||||
b dv_board_init
|
||||
|
||||
.ltorg
|
||||
|
||||
_PINMUX0:
|
||||
.word 0x01c40000 /* Device Configuration Registers */
|
||||
_PINMUX1:
|
||||
.word 0x01c40004 /* Device Configuration Registers */
|
||||
|
||||
_DEV_SETTING:
|
||||
.word 0x00000c1f
|
||||
|
||||
WAITCFG:
|
||||
.word 0x01e00004
|
||||
WAITCFG_VAL:
|
||||
.word 0
|
||||
ACFG3:
|
||||
.word 0x01e00014
|
||||
ACFG3_VAL:
|
||||
.word 0x3ffffffd
|
||||
ACFG4:
|
||||
.word 0x01e00018
|
||||
ACFG4_VAL:
|
||||
.word 0x3ffffffd
|
||||
ACFG5:
|
||||
.word 0x01e0001c
|
||||
ACFG5_VAL:
|
||||
.word 0x3ffffffd
|
||||
|
||||
MDCTL_DDR2:
|
||||
.word 0x01c41a34
|
||||
MDSTAT_DDR2:
|
||||
.word 0x01c41834
|
||||
|
||||
PTCMD:
|
||||
.word 0x01c41120
|
||||
PTSTAT:
|
||||
.word 0x01c41128
|
||||
|
||||
EINT_ENABLE0:
|
||||
.word 0x01c48018
|
||||
EINT_ENABLE1:
|
||||
.word 0x01c4801c
|
||||
|
||||
PSC_FLAG_CLEAR:
|
||||
.word 0xffffffe0
|
||||
PSC_GEM_FLAG_CLEAR:
|
||||
.word 0xfffffeff
|
||||
|
||||
/* DDR2 MMR & CONFIGURATION VALUES, 162 MHZ clock */
|
||||
DDRCTL:
|
||||
.word 0x200000e4
|
||||
DDRCTL_VAL:
|
||||
.word 0x50006405
|
||||
SDREF:
|
||||
.word 0x2000000c
|
||||
SDREF_VAL:
|
||||
.word 0x000005c3
|
||||
SDCFG:
|
||||
.word 0x20000008
|
||||
SDCFG_VAL:
|
||||
#ifdef DDR_4BANKS
|
||||
.word 0x00178622
|
||||
#elif defined DDR_8BANKS
|
||||
.word 0x00178632
|
||||
#else
|
||||
#error "Unknown DDR configuration!!!"
|
||||
#endif
|
||||
SDTIM0:
|
||||
.word 0x20000010
|
||||
SDTIM0_VAL_162MHz:
|
||||
.word 0x28923211
|
||||
SDTIM1:
|
||||
.word 0x20000014
|
||||
SDTIM1_VAL_162MHz:
|
||||
.word 0x0016c722
|
||||
VTPIOCR:
|
||||
.word 0x200000f0 /* VTP IO Control register */
|
||||
DDRVTPR:
|
||||
.word 0x01c42030 /* DDR VPTR MMR */
|
||||
VTP_MMR0:
|
||||
.word 0x201f
|
||||
VTP_MMR1:
|
||||
.word 0xa01f
|
||||
DFT_ENABLE:
|
||||
.word 0x01c4004c
|
||||
VTP_LOCK_COUNT:
|
||||
.word 0x5b0
|
||||
VTP_MASK:
|
||||
.word 0xffffdfff
|
||||
VTP_RECAL:
|
||||
.word 0x40000
|
||||
VTP_EN:
|
||||
.word 0x02000
|
||||
CFGTEST:
|
||||
.word 0x80010000
|
||||
MASK_VAL:
|
||||
.word 0x00000fff
|
||||
|
||||
/* GEM Power Up & LPSC Control Register */
|
||||
MDCTL_GEM:
|
||||
.word 0x01c41a9c
|
||||
MDSTAT_GEM:
|
||||
.word 0x01c4189c
|
||||
|
||||
/* For WDT reset chip bug */
|
||||
P1394:
|
||||
.word 0x01c41a20
|
||||
|
||||
PLL_CLKSRC_MASK:
|
||||
.word 0xfffffeff /* Mask the Clock Mode bit */
|
||||
PLL_ENSRC_MASK:
|
||||
.word 0xffffffdf /* Select the PLLEN source */
|
||||
PLL_BYPASS_MASK:
|
||||
.word 0xfffffffe /* Put the PLL in BYPASS */
|
||||
PLL_RESET_MASK:
|
||||
.word 0xfffffff7 /* Put the PLL in Reset Mode */
|
||||
PLL_PWRUP_MASK:
|
||||
.word 0xfffffffd /* PLL Power up Mask Bit */
|
||||
PLL_DISABLE_ENABLE_MASK:
|
||||
.word 0xffffffef /* Enable the PLL from Disable */
|
||||
PLL_LOCK_COUNT:
|
||||
.word 0x2000
|
||||
|
||||
/* PLL1-SYSTEM PLL MMRs */
|
||||
PLL1_CTL:
|
||||
.word 0x01c40900
|
||||
PLL1_PLLM:
|
||||
.word 0x01c40910
|
||||
|
||||
/* PLL2-SYSTEM PLL MMRs */
|
||||
PLL2_CTL:
|
||||
.word 0x01c40d00
|
||||
PLL2_PLLM:
|
||||
.word 0x01c40d10
|
||||
PLL2_DIV1:
|
||||
.word 0x01c40d18
|
||||
PLL2_DIV2:
|
||||
.word 0x01c40d1c
|
||||
PLL2_PLLCMD:
|
||||
.word 0x01c40d38
|
||||
PLL2_PLLSTAT:
|
||||
.word 0x01c40d3c
|
||||
PLL2_DIV_MASK:
|
||||
.word 0xffff7fff
|
||||
|
||||
MMARG_BRF0:
|
||||
.word 0x01c42010 /* BRF margin mode 0 (R/W)*/
|
||||
MMARG_BRF0_VAL:
|
||||
.word 0x00444400
|
||||
|
||||
DDR2_START_ADDR:
|
||||
.word 0x80000000
|
||||
DUMMY_VAL:
|
||||
.word 0xa55aa55a
|
||||
142
cpu/arm926ejs/davinci/lxt972.c
Normal file
142
cpu/arm926ejs/davinci/lxt972.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Intel LXT971/LXT972 PHY Driver for TI DaVinci
|
||||
* (TMS320DM644x) based boards.
|
||||
*
|
||||
* Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
|
||||
*
|
||||
* --------------------------------------------------------
|
||||
*
|
||||
* 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 <net.h>
|
||||
#include <lxt971a.h>
|
||||
#include <asm/arch/emac_defs.h>
|
||||
|
||||
#ifdef CONFIG_DRIVER_TI_EMAC
|
||||
|
||||
#ifdef CONFIG_CMD_NET
|
||||
|
||||
int lxt972_is_phy_connected(int phy_addr)
|
||||
{
|
||||
u_int16_t id1, id2;
|
||||
|
||||
if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_ID1, &id1))
|
||||
return(0);
|
||||
if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_ID2, &id2))
|
||||
return(0);
|
||||
|
||||
if ((id1 == (0x0013)) && ((id2 & 0xfff0) == 0x78e0))
|
||||
return(1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int lxt972_get_link_speed(int phy_addr)
|
||||
{
|
||||
u_int16_t stat1, tmp;
|
||||
volatile emac_regs* emac = (emac_regs *)EMAC_BASE_ADDR;
|
||||
|
||||
if (!dm644x_eth_phy_read(phy_addr, PHY_LXT971_STAT2, &stat1))
|
||||
return(0);
|
||||
|
||||
if (!(stat1 & PHY_LXT971_STAT2_LINK)) /* link up? */
|
||||
return(0);
|
||||
|
||||
if (!dm644x_eth_phy_read(phy_addr, PHY_LXT971_DIG_CFG, &tmp))
|
||||
return(0);
|
||||
|
||||
tmp |= PHY_LXT971_DIG_CFG_MII_DRIVE;
|
||||
|
||||
dm644x_eth_phy_write(phy_addr, PHY_LXT971_DIG_CFG, tmp);
|
||||
/* Read back */
|
||||
if (!dm644x_eth_phy_read(phy_addr, PHY_LXT971_DIG_CFG, &tmp))
|
||||
return(0);
|
||||
|
||||
|
||||
/* Speed doesn't matter, there is no setting for it in EMAC... */
|
||||
if (stat1 & PHY_LXT971_STAT2_100BTX) {
|
||||
if (stat1 & PHY_LXT971_STAT2_DUPLEX_MODE) {
|
||||
/* set DM644x EMAC for Full Duplex */
|
||||
emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE;
|
||||
} else {
|
||||
/*set DM644x EMAC for Half Duplex */
|
||||
emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE;
|
||||
}
|
||||
|
||||
return(1);
|
||||
} else {
|
||||
if (stat1 & PHY_LXT971_STAT2_DUPLEX_MODE) {
|
||||
/* set DM644x EMAC for Full Duplex */
|
||||
emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE;
|
||||
} else {
|
||||
/*set DM644x EMAC for Half Duplex */
|
||||
emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE;
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
int lxt972_init_phy(int phy_addr)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
if (!lxt972_get_link_speed(phy_addr)) {
|
||||
/* Try another time */
|
||||
ret = lxt972_get_link_speed(phy_addr);
|
||||
}
|
||||
|
||||
/* Disable PHY Interrupts */
|
||||
dm644x_eth_phy_write(phy_addr, PHY_LXT971_INT_ENABLE, 0);
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
int lxt972_auto_negotiate(int phy_addr)
|
||||
{
|
||||
u_int16_t tmp;
|
||||
|
||||
|
||||
if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_CTRL, &tmp))
|
||||
return(0);
|
||||
|
||||
/* Restart Auto_negotiation */
|
||||
tmp |= PHY_COMMON_CTRL_RES_AUTO;
|
||||
dm644x_eth_phy_write(phy_addr, PHY_COMMON_CTRL, tmp);
|
||||
|
||||
/*check AutoNegotiate complete */
|
||||
udelay (10000);
|
||||
if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_STAT, &tmp))
|
||||
return(0);
|
||||
|
||||
if (!(tmp & PHY_COMMON_STAT_AN_COMP))
|
||||
return(0);
|
||||
|
||||
return (lxt972_get_link_speed(phy_addr));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CMD_NET */
|
||||
|
||||
#endif /* CONFIG_DRIVER_ETHER */
|
||||
389
cpu/arm926ejs/davinci/nand.c
Normal file
389
cpu/arm926ejs/davinci/nand.c
Normal file
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
* NAND driver for TI DaVinci based boards.
|
||||
*
|
||||
* Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
|
||||
*
|
||||
* Based on Linux DaVinci NAND driver by TI. Original copyright follows:
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* linux/drivers/mtd/nand/nand_davinci.c
|
||||
*
|
||||
* NAND Flash Driver
|
||||
*
|
||||
* Copyright (C) 2006 Texas Instruments.
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
* Overview:
|
||||
* This is a device driver for the NAND flash device found on the
|
||||
* DaVinci board which utilizes the Samsung k9k2g08 part.
|
||||
*
|
||||
Modifications:
|
||||
ver. 1.0: Feb 2005, Vinod/Sudhakar
|
||||
-
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#ifdef CFG_USE_NAND
|
||||
#if !defined(CFG_NAND_LEGACY)
|
||||
|
||||
#include <nand.h>
|
||||
#include <asm/arch/nand_defs.h>
|
||||
#include <asm/arch/emif_defs.h>
|
||||
|
||||
extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
|
||||
|
||||
static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd)
|
||||
{
|
||||
struct nand_chip *this = mtd->priv;
|
||||
u_int32_t IO_ADDR_W = (u_int32_t)this->IO_ADDR_W;
|
||||
|
||||
IO_ADDR_W &= ~(MASK_ALE|MASK_CLE);
|
||||
|
||||
switch (cmd) {
|
||||
case NAND_CTL_SETCLE:
|
||||
IO_ADDR_W |= MASK_CLE;
|
||||
break;
|
||||
case NAND_CTL_SETALE:
|
||||
IO_ADDR_W |= MASK_ALE;
|
||||
break;
|
||||
}
|
||||
|
||||
this->IO_ADDR_W = (void *)IO_ADDR_W;
|
||||
}
|
||||
|
||||
/* Set WP on deselect, write enable on select */
|
||||
static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
|
||||
{
|
||||
#define GPIO_SET_DATA01 0x01c67018
|
||||
#define GPIO_CLR_DATA01 0x01c6701c
|
||||
#define GPIO_NAND_WP (1 << 4)
|
||||
#ifdef SONATA_BOARD_GPIOWP
|
||||
if (chip < 0) {
|
||||
REG(GPIO_CLR_DATA01) |= GPIO_NAND_WP;
|
||||
} else {
|
||||
REG(GPIO_SET_DATA01) |= GPIO_NAND_WP;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CFG_NAND_HW_ECC
|
||||
#ifdef CFG_NAND_LARGEPAGE
|
||||
static struct nand_oobinfo davinci_nand_oobinfo = {
|
||||
.useecc = MTD_NANDECC_AUTOPLACE,
|
||||
.eccbytes = 12,
|
||||
.eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58},
|
||||
.oobfree = { {2, 6}, {12, 12}, {28, 12}, {44, 12}, {60, 4} }
|
||||
};
|
||||
#elif defined(CFG_NAND_SMALLPAGE)
|
||||
static struct nand_oobinfo davinci_nand_oobinfo = {
|
||||
.useecc = MTD_NANDECC_AUTOPLACE,
|
||||
.eccbytes = 3,
|
||||
.eccpos = {0, 1, 2},
|
||||
.oobfree = { {6, 2}, {8, 8} }
|
||||
};
|
||||
#else
|
||||
#error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!"
|
||||
#endif
|
||||
|
||||
static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode)
|
||||
{
|
||||
emifregs emif_addr;
|
||||
int dummy;
|
||||
|
||||
emif_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE;
|
||||
|
||||
dummy = emif_addr->NANDF1ECC;
|
||||
dummy = emif_addr->NANDF2ECC;
|
||||
dummy = emif_addr->NANDF3ECC;
|
||||
dummy = emif_addr->NANDF4ECC;
|
||||
|
||||
emif_addr->NANDFCR |= (1 << 8);
|
||||
}
|
||||
|
||||
static u_int32_t nand_davinci_readecc(struct mtd_info *mtd, u_int32_t region)
|
||||
{
|
||||
u_int32_t ecc = 0;
|
||||
emifregs emif_base_addr;
|
||||
|
||||
emif_base_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE;
|
||||
|
||||
if (region == 1)
|
||||
ecc = emif_base_addr->NANDF1ECC;
|
||||
else if (region == 2)
|
||||
ecc = emif_base_addr->NANDF2ECC;
|
||||
else if (region == 3)
|
||||
ecc = emif_base_addr->NANDF3ECC;
|
||||
else if (region == 4)
|
||||
ecc = emif_base_addr->NANDF4ECC;
|
||||
|
||||
return(ecc);
|
||||
}
|
||||
|
||||
static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
|
||||
{
|
||||
u_int32_t tmp;
|
||||
int region, n;
|
||||
struct nand_chip *this = mtd->priv;
|
||||
|
||||
n = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1;
|
||||
|
||||
region = 1;
|
||||
while (n--) {
|
||||
tmp = nand_davinci_readecc(mtd, region);
|
||||
*ecc_code++ = tmp;
|
||||
*ecc_code++ = tmp >> 16;
|
||||
*ecc_code++ = ((tmp >> 8) & 0x0f) | ((tmp >> 20) & 0xf0);
|
||||
region++;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void nand_davinci_gen_true_ecc(u_int8_t *ecc_buf)
|
||||
{
|
||||
u_int32_t tmp = ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xf0) << 20) | ((ecc_buf[2] & 0x0f) << 8);
|
||||
|
||||
ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) | P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp));
|
||||
ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) | P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp));
|
||||
ecc_buf[2] = ~( P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) | P1e(tmp) | P2048o(tmp) | P2048e(tmp));
|
||||
}
|
||||
|
||||
static int nand_davinci_compare_ecc(u_int8_t *ecc_nand, u_int8_t *ecc_calc, u_int8_t *page_data)
|
||||
{
|
||||
u_int32_t i;
|
||||
u_int8_t tmp0_bit[8], tmp1_bit[8], tmp2_bit[8];
|
||||
u_int8_t comp0_bit[8], comp1_bit[8], comp2_bit[8];
|
||||
u_int8_t ecc_bit[24];
|
||||
u_int8_t ecc_sum = 0;
|
||||
u_int8_t find_bit = 0;
|
||||
u_int32_t find_byte = 0;
|
||||
int is_ecc_ff;
|
||||
|
||||
is_ecc_ff = ((*ecc_nand == 0xff) && (*(ecc_nand + 1) == 0xff) && (*(ecc_nand + 2) == 0xff));
|
||||
|
||||
nand_davinci_gen_true_ecc(ecc_nand);
|
||||
nand_davinci_gen_true_ecc(ecc_calc);
|
||||
|
||||
for (i = 0; i <= 2; i++) {
|
||||
*(ecc_nand + i) = ~(*(ecc_nand + i));
|
||||
*(ecc_calc + i) = ~(*(ecc_calc + i));
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
tmp0_bit[i] = *ecc_nand % 2;
|
||||
*ecc_nand = *ecc_nand / 2;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
tmp1_bit[i] = *(ecc_nand + 1) % 2;
|
||||
*(ecc_nand + 1) = *(ecc_nand + 1) / 2;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
tmp2_bit[i] = *(ecc_nand + 2) % 2;
|
||||
*(ecc_nand + 2) = *(ecc_nand + 2) / 2;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
comp0_bit[i] = *ecc_calc % 2;
|
||||
*ecc_calc = *ecc_calc / 2;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
comp1_bit[i] = *(ecc_calc + 1) % 2;
|
||||
*(ecc_calc + 1) = *(ecc_calc + 1) / 2;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
comp2_bit[i] = *(ecc_calc + 2) % 2;
|
||||
*(ecc_calc + 2) = *(ecc_calc + 2) / 2;
|
||||
}
|
||||
|
||||
for (i = 0; i< 6; i++)
|
||||
ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2];
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i];
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i];
|
||||
|
||||
ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0];
|
||||
ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1];
|
||||
|
||||
for (i = 0; i < 24; i++)
|
||||
ecc_sum += ecc_bit[i];
|
||||
|
||||
switch (ecc_sum) {
|
||||
case 0:
|
||||
/* Not reached because this function is not called if
|
||||
ECC values are equal */
|
||||
return 0;
|
||||
case 1:
|
||||
/* Uncorrectable error */
|
||||
DEBUG (MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n");
|
||||
return(-1);
|
||||
case 12:
|
||||
/* Correctable error */
|
||||
find_byte = (ecc_bit[23] << 8) +
|
||||
(ecc_bit[21] << 7) +
|
||||
(ecc_bit[19] << 6) +
|
||||
(ecc_bit[17] << 5) +
|
||||
(ecc_bit[15] << 4) +
|
||||
(ecc_bit[13] << 3) +
|
||||
(ecc_bit[11] << 2) +
|
||||
(ecc_bit[9] << 1) +
|
||||
ecc_bit[7];
|
||||
|
||||
find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1];
|
||||
|
||||
DEBUG (MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at offset: %d, bit: %d\n", find_byte, find_bit);
|
||||
|
||||
page_data[find_byte] ^= (1 << find_bit);
|
||||
|
||||
return(0);
|
||||
default:
|
||||
if (is_ecc_ff) {
|
||||
if (ecc_calc[0] == 0 && ecc_calc[1] == 0 && ecc_calc[2] == 0)
|
||||
return(0);
|
||||
}
|
||||
DEBUG (MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n");
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
|
||||
{
|
||||
struct nand_chip *this;
|
||||
int block_count = 0, i, rc;
|
||||
|
||||
this = mtd->priv;
|
||||
block_count = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1;
|
||||
for (i = 0; i < block_count; i++) {
|
||||
if (memcmp(read_ecc, calc_ecc, 3) != 0) {
|
||||
rc = nand_davinci_compare_ecc(read_ecc, calc_ecc, dat);
|
||||
if (rc < 0) {
|
||||
return(rc);
|
||||
}
|
||||
}
|
||||
read_ecc += 3;
|
||||
calc_ecc += 3;
|
||||
dat += 512;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int nand_davinci_dev_ready(struct mtd_info *mtd)
|
||||
{
|
||||
emifregs emif_addr;
|
||||
|
||||
emif_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE;
|
||||
|
||||
return(emif_addr->NANDFSR & 0x1);
|
||||
}
|
||||
|
||||
static int nand_davinci_waitfunc(struct mtd_info *mtd, struct nand_chip *this, int state)
|
||||
{
|
||||
while(!nand_davinci_dev_ready(mtd)) {;}
|
||||
*NAND_CE0CLE = NAND_STATUS;
|
||||
return(*NAND_CE0DATA);
|
||||
}
|
||||
|
||||
static void nand_flash_init(void)
|
||||
{
|
||||
u_int32_t acfg1 = 0x3ffffffc;
|
||||
u_int32_t acfg2 = 0x3ffffffc;
|
||||
u_int32_t acfg3 = 0x3ffffffc;
|
||||
u_int32_t acfg4 = 0x3ffffffc;
|
||||
emifregs emif_regs;
|
||||
|
||||
/*------------------------------------------------------------------*
|
||||
* NAND FLASH CHIP TIMEOUT @ 459 MHz *
|
||||
* *
|
||||
* AEMIF.CLK freq = PLL1/6 = 459/6 = 76.5 MHz *
|
||||
* AEMIF.CLK period = 1/76.5 MHz = 13.1 ns *
|
||||
* *
|
||||
*------------------------------------------------------------------*/
|
||||
acfg1 = 0
|
||||
| (0 << 31 ) /* selectStrobe */
|
||||
| (0 << 30 ) /* extWait */
|
||||
| (1 << 26 ) /* writeSetup 10 ns */
|
||||
| (3 << 20 ) /* writeStrobe 40 ns */
|
||||
| (1 << 17 ) /* writeHold 10 ns */
|
||||
| (1 << 13 ) /* readSetup 10 ns */
|
||||
| (5 << 7 ) /* readStrobe 60 ns */
|
||||
| (1 << 4 ) /* readHold 10 ns */
|
||||
| (3 << 2 ) /* turnAround ?? ns */
|
||||
| (0 << 0 ) /* asyncSize 8-bit bus */
|
||||
;
|
||||
|
||||
emif_regs = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE;
|
||||
|
||||
emif_regs->AWCCR |= 0x10000000;
|
||||
emif_regs->AB1CR = acfg1; /* 0x08244128 */;
|
||||
emif_regs->AB2CR = acfg2;
|
||||
emif_regs->AB3CR = acfg3;
|
||||
emif_regs->AB4CR = acfg4;
|
||||
emif_regs->NANDFCR = 0x00000101;
|
||||
}
|
||||
|
||||
int board_nand_init(struct nand_chip *nand)
|
||||
{
|
||||
nand->IO_ADDR_R = (void __iomem *)NAND_CE0DATA;
|
||||
nand->IO_ADDR_W = (void __iomem *)NAND_CE0DATA;
|
||||
nand->chip_delay = 0;
|
||||
nand->select_chip = nand_davinci_select_chip;
|
||||
#ifdef CFG_NAND_USE_FLASH_BBT
|
||||
nand->options = NAND_USE_FLASH_BBT;
|
||||
#endif
|
||||
#ifdef CFG_NAND_HW_ECC
|
||||
#ifdef CFG_NAND_LARGEPAGE
|
||||
nand->eccmode = NAND_ECC_HW12_2048;
|
||||
#elif defined(CFG_NAND_SMALLPAGE)
|
||||
nand->eccmode = NAND_ECC_HW3_512;
|
||||
#else
|
||||
#error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!"
|
||||
#endif
|
||||
nand->autooob = &davinci_nand_oobinfo;
|
||||
nand->calculate_ecc = nand_davinci_calculate_ecc;
|
||||
nand->correct_data = nand_davinci_correct_data;
|
||||
nand->enable_hwecc = nand_davinci_enable_hwecc;
|
||||
#else
|
||||
nand->eccmode = NAND_ECC_SOFT;
|
||||
#endif
|
||||
|
||||
/* Set address of hardware control function */
|
||||
nand->hwcontrol = nand_davinci_hwcontrol;
|
||||
|
||||
nand->dev_ready = nand_davinci_dev_ready;
|
||||
nand->waitfunc = nand_davinci_waitfunc;
|
||||
|
||||
nand_flash_init();
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
#else
|
||||
#error "U-Boot legacy NAND support not available for DaVinci chips"
|
||||
#endif
|
||||
#endif /* CFG_USE_NAND */
|
||||
77
cpu/arm926ejs/davinci/reset.S
Normal file
77
cpu/arm926ejs/davinci/reset.S
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Processor reset using WDT for TI TMS320DM644x SoC.
|
||||
*
|
||||
* Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
|
||||
*
|
||||
* -----------------------------------------------------
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
.globl reset_cpu
|
||||
reset_cpu:
|
||||
ldr r0, WDT_TGCR
|
||||
mov r1, $0x08
|
||||
str r1, [r0]
|
||||
ldr r1, [r0]
|
||||
orr r1, r1, $0x03
|
||||
str r1, [r0]
|
||||
mov r1, $0
|
||||
ldr r0, WDT_TIM12
|
||||
str r1, [r0]
|
||||
ldr r0, WDT_TIM34
|
||||
str r1, [r0]
|
||||
ldr r0, WDT_PRD12
|
||||
str r1, [r0]
|
||||
ldr r0, WDT_PRD34
|
||||
str r1, [r0]
|
||||
ldr r0, WDT_TCR
|
||||
ldr r1, [r0]
|
||||
orr r1, r1, $0x40
|
||||
str r1, [r0]
|
||||
ldr r0, WDT_WDTCR
|
||||
ldr r1, [r0]
|
||||
orr r1, r1, $0x4000
|
||||
str r1, [r0]
|
||||
ldr r1, WDTCR_VAL1
|
||||
str r1, [r0]
|
||||
ldr r1, WDTCR_VAL2
|
||||
str r1, [r0]
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
reset_cpu_loop:
|
||||
b reset_cpu_loop
|
||||
|
||||
WDT_TGCR:
|
||||
.word 0x01c21c24
|
||||
WDT_TIM12:
|
||||
.word 0x01c21c10
|
||||
WDT_TIM34:
|
||||
.word 0x01c21c14
|
||||
WDT_PRD12:
|
||||
.word 0x01c21c18
|
||||
WDT_PRD34:
|
||||
.word 0x01c21c1c
|
||||
WDT_TCR:
|
||||
.word 0x01c21c20
|
||||
WDT_WDTCR:
|
||||
.word 0x01c21c28
|
||||
WDTCR_VAL1:
|
||||
.word 0xa5c64000
|
||||
WDTCR_VAL2:
|
||||
.word 0xda7e4000
|
||||
165
cpu/arm926ejs/davinci/timer.c
Normal file
165
cpu/arm926ejs/davinci/timer.c
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* (C) Copyright 2003
|
||||
* Texas Instruments <www.ti.com>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Marius Groeger <mgroeger@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
|
||||
* Alex Zuepke <azu@sysgo.de>
|
||||
*
|
||||
* (C) Copyright 2002-2004
|
||||
* Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
|
||||
*
|
||||
* (C) Copyright 2004
|
||||
* Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
|
||||
*
|
||||
* Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
|
||||
*
|
||||
* 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 <arm926ejs.h>
|
||||
|
||||
typedef volatile struct {
|
||||
u_int32_t pid12;
|
||||
u_int32_t emumgt_clksped;
|
||||
u_int32_t gpint_en;
|
||||
u_int32_t gpdir_dat;
|
||||
u_int32_t tim12;
|
||||
u_int32_t tim34;
|
||||
u_int32_t prd12;
|
||||
u_int32_t prd34;
|
||||
u_int32_t tcr;
|
||||
u_int32_t tgcr;
|
||||
u_int32_t wdtcr;
|
||||
u_int32_t tlgc;
|
||||
u_int32_t tlmr;
|
||||
} davinci_timer;
|
||||
|
||||
davinci_timer *timer = (davinci_timer *)CFG_TIMERBASE;
|
||||
|
||||
#define TIMER_LOAD_VAL (CFG_HZ_CLOCK / CFG_HZ)
|
||||
#define READ_TIMER timer->tim34
|
||||
|
||||
static ulong timestamp;
|
||||
static ulong lastinc;
|
||||
|
||||
int timer_init(void)
|
||||
{
|
||||
/* We are using timer34 in unchained 32-bit mode, full speed */
|
||||
timer->tcr = 0x0;
|
||||
timer->tgcr = 0x0;
|
||||
timer->tgcr = 0x06;
|
||||
timer->tim34 = 0x0;
|
||||
timer->prd34 = TIMER_LOAD_VAL;
|
||||
lastinc = 0;
|
||||
timer->tcr = 0x80 << 16;
|
||||
timestamp = 0;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void reset_timer(void)
|
||||
{
|
||||
reset_timer_masked();
|
||||
}
|
||||
|
||||
ulong get_timer(ulong base)
|
||||
{
|
||||
return(get_timer_masked() - base);
|
||||
}
|
||||
|
||||
void set_timer(ulong t)
|
||||
{
|
||||
timestamp = t;
|
||||
}
|
||||
|
||||
void udelay(unsigned long usec)
|
||||
{
|
||||
udelay_masked(usec);
|
||||
}
|
||||
|
||||
void reset_timer_masked(void)
|
||||
{
|
||||
lastinc = READ_TIMER;
|
||||
timestamp = 0;
|
||||
}
|
||||
|
||||
ulong get_timer_raw(void)
|
||||
{
|
||||
ulong now = READ_TIMER;
|
||||
|
||||
if (now >= lastinc) {
|
||||
/* normal mode */
|
||||
timestamp += now - lastinc;
|
||||
} else {
|
||||
/* overflow ... */
|
||||
timestamp += now + TIMER_LOAD_VAL - lastinc;
|
||||
}
|
||||
lastinc = now;
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
ulong get_timer_masked(void)
|
||||
{
|
||||
return(get_timer_raw() / TIMER_LOAD_VAL);
|
||||
}
|
||||
|
||||
void udelay_masked(unsigned long usec)
|
||||
{
|
||||
ulong tmo;
|
||||
ulong endtime;
|
||||
signed long diff;
|
||||
|
||||
tmo = CFG_HZ_CLOCK / 1000;
|
||||
tmo *= usec;
|
||||
tmo /= 1000;
|
||||
|
||||
endtime = get_timer_raw() + tmo;
|
||||
|
||||
do {
|
||||
ulong now = get_timer_raw();
|
||||
diff = endtime - now;
|
||||
} while (diff >= 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is derived from PowerPC code (read timebase as long long).
|
||||
* On ARM it just returns the timer value.
|
||||
*/
|
||||
unsigned long long get_ticks(void)
|
||||
{
|
||||
return(get_timer(0));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is derived from PowerPC code (timebase clock frequency).
|
||||
* On ARM it returns the number of timer ticks per second.
|
||||
*/
|
||||
ulong get_tbclk(void)
|
||||
{
|
||||
ulong tbclk;
|
||||
|
||||
tbclk = CFG_HZ;
|
||||
return(tbclk);
|
||||
}
|
||||
@@ -42,7 +42,7 @@ int checkcpu (void)
|
||||
u32 spridr = immr->sysconf.spridr;
|
||||
char buf[32];
|
||||
|
||||
puts("CPU: ");
|
||||
puts ("CPU: ");
|
||||
|
||||
switch (spridr & 0xffff0000) {
|
||||
case SPR_5121E:
|
||||
|
||||
@@ -17,10 +17,10 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
|
||||
#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \
|
||||
defined(CONFIG_MPC512x_FEC)
|
||||
|
||||
#if !(defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII))
|
||||
#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
|
||||
#error "CONFIG_MII has to be defined!"
|
||||
#endif
|
||||
|
||||
@@ -626,7 +626,7 @@ int mpc512x_fec_initialize (bd_t * bis)
|
||||
sprintf (dev->name, "FEC ETHERNET");
|
||||
eth_register (dev);
|
||||
|
||||
#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
||||
miiphy_register (dev->name,
|
||||
fec512x_miiphy_read, fec512x_miiphy_write);
|
||||
#endif
|
||||
|
||||
@@ -106,7 +106,7 @@ MachineCheckException (struct pt_regs *regs)
|
||||
return;
|
||||
}
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
#ifdef CONFIG_CMD_KGDB
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
@@ -144,7 +144,7 @@ MachineCheckException (struct pt_regs *regs)
|
||||
void
|
||||
AlignmentException (struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
#ifdef CONFIG_CMD_KGDB
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
@@ -156,7 +156,7 @@ AlignmentException (struct pt_regs *regs)
|
||||
void
|
||||
ProgramCheckException (struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
#ifdef CONFIG_CMD_KGDB
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
@@ -168,7 +168,7 @@ ProgramCheckException (struct pt_regs *regs)
|
||||
void
|
||||
SoftEmuException (struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
#ifdef CONFIG_CMD_KGDB
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
@@ -181,7 +181,7 @@ SoftEmuException (struct pt_regs *regs)
|
||||
void
|
||||
UnknownException (struct pt_regs *regs)
|
||||
{
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
|
||||
#ifdef CONFIG_CMD_KGDB
|
||||
if (debugger_exception_handler && (*debugger_exception_handler)(regs))
|
||||
return;
|
||||
#endif
|
||||
@@ -190,7 +190,7 @@ UnknownException (struct pt_regs *regs)
|
||||
_exception (0, regs);
|
||||
}
|
||||
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
|
||||
#ifdef CONFIG_CMD_BEDBUG
|
||||
extern void do_bedbug_breakpoint (struct pt_regs *);
|
||||
#endif
|
||||
|
||||
@@ -199,7 +199,7 @@ DebugException (struct pt_regs *regs)
|
||||
{
|
||||
printf ("Debugger trap at @ %lx\n", regs->nip );
|
||||
show_regs (regs);
|
||||
#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG)
|
||||
#ifdef CONFIG_CMD_BEDBUG
|
||||
do_bedbug_breakpoint (regs);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -576,7 +576,7 @@ long int spd_sdram()
|
||||
if (spd.dataw_lsb == 0x20) {
|
||||
if (spd.mem_type == SPD_MEMTYPE_DDR)
|
||||
burstlen = 0x03; /* 32 bit data bus, burst len is 8 */
|
||||
if (spd.mem_type == SPD_MEMTYPE_DDR2)
|
||||
else
|
||||
burstlen = 0x02; /* 32 bit data bus, burst len is 4 */
|
||||
printf("\n DDR DIMM: data bus width is 32 bit");
|
||||
} else {
|
||||
|
||||
@@ -34,7 +34,7 @@ int checkcpu (void)
|
||||
|
||||
/* Get cpu version info */
|
||||
val = rdctl (CTL_CPU_ID);
|
||||
printf ("CPU: ");
|
||||
puts ("CPU: ");
|
||||
printf ("%s", (val & 0x00008000) ? "Nios-16 " : "Nios-32 ");
|
||||
rev_major = (val>>12) & 0x07;
|
||||
rev_minor = (val>>4) & 0x0ff;
|
||||
|
||||
Reference in New Issue
Block a user