summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJosh Wu <josh.wu@atmel.com>2012-10-22 15:49:04 +0800
committerJosh Wu <josh.wu@atmel.com>2012-10-22 15:49:04 +0800
commitd09dc68d74844b44b89a1311f60055351952fb0e (patch)
tree6d4bf5d6962bfa3c5d4597d8fbcdb7e2fd840266 /drivers
parent6528ff0109d81c1f21d20f9f1370782bccf87bcb (diff)
parent3cda03c7fa4413eef2ee250b5936a88c25dbc1be (diff)
Merge branch 'josh/sama5ek/v2012.10-rc1' into josh/sama5ek/v2012.10
Conflicts: drivers/mtd/spi/atmel.c
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/gen_atmel_mci.c11
-rw-r--r--drivers/mtd/nand/nand_ids.c1
-rw-r--r--drivers/mtd/spi/atmel.c309
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/gmacb.c622
-rw-r--r--drivers/net/gmacb.h266
-rw-r--r--drivers/net/macb.c6
-rw-r--r--drivers/usb/host/ohci-at91.c8
-rw-r--r--drivers/video/atmel_lcdfb.c192
9 files changed, 1400 insertions, 16 deletions
diff --git a/drivers/mmc/gen_atmel_mci.c b/drivers/mmc/gen_atmel_mci.c
index 4968c5e491..1e104f6fe1 100644
--- a/drivers/mmc/gen_atmel_mci.c
+++ b/drivers/mmc/gen_atmel_mci.c
@@ -83,10 +83,17 @@ static void mci_set_mode(struct mmc *mmc, u32 hz, u32 blklen)
blklen &= 0xfffc;
/* On some platforms RDPROOF and WRPROOF are ignored */
+#ifdef CONFIG_AT91SAMA5
+ writel((MMCI_BF(CLKDIV, clkdiv)
+ | MMCI_BIT(RDPROOF)
+ | MMCI_BIT(WRPROOF)), &mci->mr);
+ writel((blklen << 16), &mci->blkr);
+#else
writel((MMCI_BF(CLKDIV, clkdiv)
| MMCI_BF(BLKLEN, blklen)
| MMCI_BIT(RDPROOF)
| MMCI_BIT(WRPROOF)), &mci->mr);
+#endif
initialized = 1;
}
@@ -183,6 +190,10 @@ mci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
/* Figure out the transfer arguments */
cmdr = mci_encode_cmd(cmd, data, &error_flags);
+ if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK)
+ || (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK))
+ writel(data->blocks | mmc->read_bl_len << 16, &mci->blkr);
+
/* Send the command */
writel(cmd->cmdarg, &mci->argr);
writel(cmdr, &mci->cmdr);
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 39535497f8..0e69ac8ba0 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -107,6 +107,7 @@ const struct nand_flash_dev nand_flash_ids[] = {
/* 8 Gigabit */
{"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS},
+ {"NAND 1GiB 3,3V 8-bit", 0x38, 0, 1024, 0, LP_OPTIONS},
{"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16},
{"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16},
diff --git a/drivers/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c
index 006f6d5d04..2f5e83f040 100644
--- a/drivers/mtd/spi/atmel.c
+++ b/drivers/mtd/spi/atmel.c
@@ -25,6 +25,33 @@
#define AT45_STATUS_P2_PAGE_SIZE (1 << 0)
#define AT45_STATUS_READY (1 << 7)
+/* AT25-specific commands */
+#define CMD_AT25_READ_STATUS 0x05
+#define CMD_AT25_WRITE_STATUS 0x01
+
+#define CMD_AT25_BYTE_PAGE_PROGRAM 0x02
+#define CMD_AT25_ERASE_BLOCK_4K 0x20
+#define CMD_AT25_ERASE_BLOCK_32K 0x52
+#define CMD_AT25_ERASE_BLOCK_64K 0xD8
+
+#define CMD_AT25_WRITE_ENABLE 0x06
+#define CMD_AT25_WRITE_DISABLE 0x04
+
+/* AT25 status register bits */
+#define AT25_STATUS_READYBUSY (1 << 0)
+#define AT25_STATUS_READYBUSY_READY (0 << 0)
+#define AT25_STATUS_READYBUSY_BUSY (1 << 0)
+#define AT25_ERASE_PROGRAM_ERROR (1 << 5)
+#define AT25_STATUS_SWP (3 << 2)
+#define AT25_STATUS_SWP_PROTECTALL (3 << 2)
+#define AT25_STATUS_SWP_PROTECTSOME (1 << 2)
+#define AT25_STATUS_SWP_PROTECTNONE (0 << 2)
+#define AT25_STATUS_SPRL (1 << 7)
+#define AT25_STATUS_SPRL_UNLOCKED (0 << 7)
+#define AT25_STATUS_SPRL_LOCKED (1 << 7)
+
+#define BLOCK_SIZE_4K (4 * 1024)
+
/* DataFlash family IDs, as obtained from the second idcode byte */
#define DF_FAMILY_AT26F 0
#define DF_FAMILY_AT45 1
@@ -111,10 +138,10 @@ static const struct atmel_spi_flash_params atmel_spi_flash_table[] = {
},
{
.idcode1 = 0x47,
- .l2_page_size = 8,
- .pages_per_block = 16,
- .blocks_per_sector = 16,
- .nr_sectors = 64,
+ .l2_page_size = 8, /* 256 bytes per page */
+ .pages_per_block = 16, /* 4k bytes per block */
+ .blocks_per_sector = 16, /* 64k bytes per sector*/
+ .nr_sectors = 64, /* 64 sectors */
.name = "AT25DF321",
},
};
@@ -178,6 +205,20 @@ static void at45_build_address(struct atmel_spi_flash *asf, u8 *cmd, u32 offset)
cmd[2] = byte_addr;
}
+static int dataflash_read_fast_p2(struct spi_flash *flash,
+ u32 offset, size_t len, void *buf)
+{
+ u8 cmd[5];
+
+ cmd[0] = CMD_READ_ARRAY_FAST;
+ cmd[1] = offset >> 16;
+ cmd[2] = offset >> 8;
+ cmd[3] = offset;
+ cmd[4] = 0x00;
+
+ return spi_flash_read_common(flash, cmd, sizeof(cmd), buf, len);
+}
+
static int dataflash_read_fast_at45(struct spi_flash *flash,
u32 offset, size_t len, void *buf)
{
@@ -336,7 +377,7 @@ out:
/*
* TODO: the two erase funcs (_p2/_at45) should get unified ...
*/
-static int dataflash_erase_p2(struct spi_flash *flash, u32 offset, size_t len)
+int dataflash_erase_p2(struct spi_flash *flash, u32 offset, size_t len)
{
struct atmel_spi_flash *asf = to_atmel_spi_flash(flash);
unsigned long page_size;
@@ -395,7 +436,7 @@ out:
return ret;
}
-static int dataflash_erase_at45(struct spi_flash *flash, u32 offset, size_t len)
+int dataflash_erase_at45(struct spi_flash *flash, u32 offset, size_t len)
{
struct atmel_spi_flash *asf = to_atmel_spi_flash(flash);
unsigned long page_addr;
@@ -458,10 +499,259 @@ out:
return ret;
}
+static int at25_read_status(struct spi_flash *flash)
+{
+ struct spi_slave *spi = flash->spi;
+ int ret;
+ u8 cmd = CMD_AT25_READ_STATUS;
+ u8 status;
+
+ ret = spi_flash_cmd_read(spi, &cmd, 1, &status, 1);
+
+ if (ret < 0) {
+ debug("SF: Error occured when read AT25 status\n");
+ return ret;
+ } else
+ return status;
+}
+
+static int at25_wait_ready(struct spi_flash *flash, unsigned long timeout)
+{
+ unsigned long timebase;
+ int ret;
+ u8 status;
+
+ timebase = get_timer(0);
+
+ do {
+ ret = at25_read_status(flash);
+ if (ret < 0)
+ return -1;
+ else
+ status = ret;
+
+ if ((status & AT25_STATUS_READYBUSY)
+ == AT25_STATUS_READYBUSY_READY)
+ break;
+ } while (get_timer(timebase) < timeout);
+
+ if ((status & AT25_STATUS_READYBUSY) == AT25_STATUS_READYBUSY_READY)
+ return 0;
+
+ /* Timed out */
+ return -1;
+}
+
+static int at25_write_status(struct spi_flash *flash, u8 data)
+{
+ struct spi_slave *spi = flash->spi;
+ u8 cmd = CMD_AT25_WRITE_STATUS;
+
+ return spi_flash_cmd_write(spi, &cmd, 1, &data, 1);
+}
+
+static int at25_write_enable(struct spi_flash *flash, int is_enable)
+{
+ struct spi_slave *spi = flash->spi;
+ int ret;
+ u8 cmd;
+
+ if (is_enable)
+ cmd = CMD_AT25_WRITE_ENABLE;
+ else
+ cmd = CMD_AT25_WRITE_DISABLE;
+
+ ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
+ if (ret)
+ return -1;
+
+ /* Deactivate CS */
+ spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);
+
+ return 0;
+}
+
+static int at25_unprotect(struct spi_flash *flash)
+{
+ int ret;
+ u8 status;
+
+ ret = at25_read_status(flash);
+ if (ret < 0)
+ debug("SF: Read AT25 status failed\n");
+ else
+ status = ret;
+
+ if ((status & AT25_STATUS_SWP) == AT25_STATUS_SWP_PROTECTNONE) {
+ /* Protection already disabled */
+ return 0;
+ }
+
+ /* Check if sector protection registers are locked */
+ if ((status & AT25_STATUS_SPRL) == AT25_STATUS_SPRL_LOCKED) {
+ /* Unprotect sector protection registers. */
+ at25_write_enable(flash, 1);
+ at25_write_status(flash, 0);
+ }
+
+ /* Perform a global unprotect command */
+ at25_write_enable(flash, 1);
+ at25_write_status(flash, 0);
+
+ /* Check the new status */
+ status = at25_read_status(flash);
+ if (ret < 0)
+ return -1;
+
+ if ((status & (AT25_STATUS_SPRL | AT25_STATUS_SWP)) != 0) {
+ debug("SF: Unprotect AT25 failed\n");
+ return -1;
+ } else
+ return 0;
+}
+
+int dataflash_erase_block_at25(struct spi_flash *flash, u32 offset)
+{
+ /* Using 4k block erase. */
+ u32 addr = offset;
+ int ret;
+ u8 cmd[4];
+
+ if (offset % BLOCK_SIZE_4K != 0)
+ return -1;
+
+ ret = at25_write_enable(flash, 1);
+ if (ret < 0) {
+ debug("SF: Enable write AT25 failed\n");
+ return ret;
+ }
+
+ cmd[0] = CMD_AT25_ERASE_BLOCK_4K;
+ cmd[1] = addr >> 16;
+ cmd[2] = addr >> 8;
+ cmd[3] = addr;
+ ret = spi_flash_cmd_write(flash->spi, cmd, 4, NULL, 0);
+ if (ret < 0) {
+ debug("SF: AT25 4k block erase failed\n");
+ return ret;
+ }
+
+ ret = at25_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
+ if (ret < 0) {
+ debug("SF: AT25 4k block erase timed out\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int dataflash_erase_at25(struct spi_flash *flash, u32 offset, size_t len)
+{
+ int ret;
+ u32 addr;
+
+ /*
+ * TODO: This function currently uses 4k block erase only. We can
+ * probably speed things up by using 32k/64k block erase or chip
+ * erase when possible.
+ */
+
+ if (offset % BLOCK_SIZE_4K || len % BLOCK_SIZE_4K) {
+ debug("SF: Erase offset/length not multiple of block size\n");
+ return -1;
+ }
+
+ ret = spi_claim_bus(flash->spi);
+ if (ret) {
+ debug("SF: Unable to claim SPI bus\n");
+ return ret;
+ }
+
+ ret = at25_unprotect(flash);
+ if (ret < 0)
+ goto out;
+
+ /* Use 4k block erase. */
+ for (addr = offset; addr < offset + len; addr += BLOCK_SIZE_4K) {
+ if (offset % BLOCK_SIZE_4K != 0)
+ addr = (addr >> 12) << 12; /* 4k size align. */
+
+ ret = dataflash_erase_block_at25(flash, addr);
+ if (ret < 0)
+ goto out;
+ }
+
+ debug("SF: AT25: Successfully erased %zu bytes @ 0x%x\n",
+ len, offset);
+ ret = 0;
+out:
+ spi_release_bus(flash->spi);
+ return ret;
+}
+
+int dataflash_write_at25(struct spi_flash *flash,
+ u32 offset, size_t len, const void *buf)
+{
+ struct atmel_spi_flash *asf = to_atmel_spi_flash(flash);
+ unsigned long page_size;
+ size_t chunk_len;
+ size_t actual;
+ int ret;
+ u8 status;
+ u32 addr;
+ u8 cmd[4];
+ u8 *data = (u8 *)buf;
+
+ page_size = 1 << (asf->params->l2_page_size);
+
+ ret = spi_claim_bus(flash->spi);
+ if (ret) {
+ debug("SF: Unable to claim SPI bus\n");
+ return ret;
+ }
+
+ ret = at25_read_status(flash);
+ if (ret < 0)
+ goto out;
+ else
+ status = ret;
+
+ /* Using page programming. */
+ for (actual = 0; actual < len; actual += chunk_len, data += chunk_len) {
+ chunk_len = min(page_size, len - actual);
+ /* using page programming. */
+ ret = at25_write_enable(flash, 1);
+ if (ret < 0)
+ goto out;
+
+ addr = offset + actual;
+ cmd[0] = CMD_AT25_BYTE_PAGE_PROGRAM;
+ cmd[1] = addr >> 16;
+ cmd[2] = addr >> 8;
+ cmd[3] = addr;
+
+ ret = spi_flash_cmd_write(flash->spi, cmd, 4, data, chunk_len);
+ if (ret < 0) {
+ debug("SF: Page programming AT25 failed\n");
+ goto out;
+ }
+
+ ret = at25_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
+ if (ret < 0) {
+ debug("SF: AT25 page programming timed out\n");
+ goto out;
+ }
+ }
+
+out:
+ spi_release_bus(flash->spi);
+ return 0;
+}
+
struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode)
{
const struct atmel_spi_flash_params *params;
- unsigned page_size;
+ unsigned long page_size;
unsigned int family;
struct atmel_spi_flash *asf;
unsigned int i;
@@ -513,7 +803,7 @@ struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode)
asf->flash.erase = dataflash_erase_at45;
page_size += 1 << (params->l2_page_size - 5);
} else {
- asf->flash.read = spi_flash_cmd_read_fast;
+ asf->flash.read = dataflash_read_fast_p2;
asf->flash.write = dataflash_write_p2;
asf->flash.erase = dataflash_erase_p2;
}
@@ -542,6 +832,9 @@ struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode)
* params->blocks_per_sector
* params->nr_sectors;
+ debug("SF: Detected %s with page size %lu, total %u bytes\n",
+ params->name, page_size, asf->flash.size);
+
return &asf->flash;
err:
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e4abac7c8f..b1da93f8f2 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -52,6 +52,7 @@ COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
COBJS-$(CONFIG_LAN91C96) += lan91c96.o
COBJS-$(CONFIG_MACB) += macb.o
+COBJS-$(CONFIG_GMACB) += gmacb.o
COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
COBJS-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o
COBJS-$(CONFIG_MPC512x_FEC) += mpc512x_fec.o
diff --git a/drivers/net/gmacb.c b/drivers/net/gmacb.c
new file mode 100644
index 0000000000..af1f552ab0
--- /dev/null
+++ b/drivers/net/gmacb.c
@@ -0,0 +1,622 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * 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>
+
+/*
+ * The u-boot networking stack is a little weird. It seems like the
+ * networking core allocates receive buffers up front without any
+ * regard to the hardware that's supposed to actually receive those
+ * packets.
+ *
+ * The MACB receives packets into 128-byte receive buffers, so the
+ * buffers allocated by the core isn't very practical to use. We'll
+ * allocate our own, but we need one such buffer in case a packet
+ * wraps around the DMA ring so that we have to copy it.
+ *
+ * Therefore, define CONFIG_SYS_RX_ETH_BUFFER to 1 in the board-specific
+ * configuration header. This way, the core allocates one RX buffer
+ * and one TX buffer, each of which can hold a ethernet packet of
+ * maximum size.
+ *
+ * For some reason, the networking core unconditionally specifies a
+ * 32-byte packet "alignment" (which really should be called
+ * "padding"). MACB shouldn't need that, but we'll refrain from any
+ * core modifications here...
+ */
+
+#include <net.h>
+#include <netdev.h>
+#include <malloc.h>
+#include <miiphy.h>
+
+#include <linux/mii.h>
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+#include <asm/arch/clk.h>
+
+#include "gmacb.h"
+
+#define barrier() asm volatile("" ::: "memory")
+
+#define CONFIG_SYS_MACB_RX_BUFFER_SIZE 4096
+#define CONFIG_SYS_MACB_RX_RING_SIZE (CONFIG_SYS_MACB_RX_BUFFER_SIZE / 128)
+#define CONFIG_SYS_MACB_TX_RING_SIZE 16
+#define CONFIG_SYS_MACB_TX_TIMEOUT 1000
+#define CONFIG_SYS_MACB_AUTONEG_TIMEOUT 5000000
+
+struct macb_dma_desc {
+ u32 addr;
+ u32 ctrl;
+} __attribute__ ((packed, aligned(8)));
+
+#define RXADDR_USED 0x00000001
+#define RXADDR_WRAP 0x00000002
+
+#define RXBUF_FRMLEN_MASK 0x00001fff
+#define RXBUF_FRAME_START 0x00004000
+#define RXBUF_FRAME_END 0x00008000
+#define RXBUF_TYPEID_MATCH 0x00400000
+#define RXBUF_ADDR4_MATCH 0x06000000
+#define RXBUF_ADDR3_MATCH 0x04000000
+#define RXBUF_ADDR2_MATCH 0x02000000
+#define RXBUF_ADDR1_MATCH 0x00000000
+#define RXBUF_BROADCAST 0x80000000
+
+#define TXBUF_FRMLEN_MASK 0x00003fff
+#define TXBUF_FRAME_END 0x00008000
+#define TXBUF_NOCRC 0x00010000
+#define TXBUF_FCS_ERR 0x00700000
+#define TXBUF_COL 0x04000000
+#define TXBUF_FRAME_COR 0x08000000
+#define TXBUF_UNDERRUN 0x10000000
+#define TXBUF_MAXRETRY 0x20000000
+#define TXBUF_WRAP 0x40000000
+#define TXBUF_USED 0x80000000
+
+struct macb_device {
+ void *regs;
+
+ unsigned int rx_tail;
+ unsigned int tx_head;
+ unsigned int tx_tail;
+
+ void *rx_buffer;
+ void *tx_buffer;
+ struct macb_dma_desc *rx_ring;
+ struct macb_dma_desc *tx_ring;
+
+ unsigned long rx_buffer_dma;
+ unsigned long rx_ring_dma;
+ unsigned long tx_ring_dma;
+
+ const struct device *dev;
+ struct eth_device netdev;
+ unsigned short phy_addr;
+};
+#define to_macb(_nd) container_of(_nd, struct macb_device, netdev)
+
+static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
+{
+ unsigned long netctl;
+ unsigned long netstat;
+ unsigned long frame;
+
+ netctl = macb_readl(macb, NCR);
+ netctl |= MACB_BIT(MPE);
+ macb_writel(macb, NCR, netctl);
+
+ frame = (MACB_BF(CLTTO, 1)
+ | MACB_BF(OP, 1)
+ | MACB_BF(PHYA, macb->phy_addr)
+ | MACB_BF(REGA, reg)
+ | MACB_BF(WTN, 2)
+ | MACB_BF(DATA, value));
+ macb_writel(macb, MAN, frame);
+
+ do {
+ netstat = macb_readl(macb, NSR);
+ } while (!(netstat & MACB_BIT(IDLE)));
+
+ netctl = macb_readl(macb, NCR);
+ netctl &= ~MACB_BIT(MPE);
+ macb_writel(macb, NCR, netctl);
+}
+
+static u16 macb_mdio_read(struct macb_device *macb, u8 reg)
+{
+ unsigned long netctl;
+ unsigned long netstat;
+ unsigned long frame;
+
+ netctl = macb_readl(macb, NCR);
+ netctl |= MACB_BIT(MPE);
+ macb_writel(macb, NCR, netctl);
+
+ frame = (MACB_BF(CLTTO, 1)
+ | MACB_BF(OP, 2)
+ | MACB_BF(PHYA, macb->phy_addr)
+ | MACB_BF(REGA, reg)
+ | MACB_BF(WTN, 2));
+ macb_writel(macb, MAN, frame);
+
+ do {
+ netstat = macb_readl(macb, NSR);
+ } while (!(netstat & MACB_BIT(IDLE)));
+
+ frame = macb_readl(macb, MAN);
+
+ netctl = macb_readl(macb, NCR);
+ netctl &= ~MACB_BIT(MPE);
+ macb_writel(macb, NCR, netctl);
+
+ return MACB_BFEXT(DATA, frame);
+}
+
+#if defined(CONFIG_CMD_MII)
+
+int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct macb_device *macb = to_macb(dev);
+
+ if ( macb->phy_addr != phy_adr )
+ return -1;
+
+ *value = macb_mdio_read(macb, reg);
+
+ return 0;
+}
+
+int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value)
+{
+ struct eth_device *dev = eth_get_dev_by_name(devname);
+ struct macb_device *macb = to_macb(dev);
+
+ if ( macb->phy_addr != phy_adr )
+ return -1;
+
+ macb_mdio_write(macb, reg, value);
+
+ return 0;
+}
+#endif
+
+
+#if defined(CONFIG_CMD_NET)
+
+static int macb_send(struct eth_device *netdev, volatile void *packet,
+ int length)
+{
+ struct macb_device *macb = to_macb(netdev);
+ unsigned long paddr, ctrl;
+ unsigned int tx_head = macb->tx_head;
+ int i;
+
+ paddr = dma_map_single(packet, length, DMA_TO_DEVICE);
+
+ macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | macb_readl(macb, NCR));
+ ctrl = length & TXBUF_FRMLEN_MASK;
+ ctrl |= TXBUF_FRAME_END;
+ if (tx_head == (CONFIG_SYS_MACB_TX_RING_SIZE - 1)) {
+ ctrl |= TXBUF_WRAP;
+ macb->tx_head = 0;
+ } else
+ macb->tx_head++;
+
+ macb->tx_ring[tx_head].ctrl = ctrl;
+ macb->tx_ring[tx_head].addr = paddr;
+ barrier();
+
+ macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE) | MACB_BIT(TSTART));
+
+ /*
+ * I guess this is necessary because the networking core may
+ * re-use the transmit buffer as soon as we return...
+ */
+ for (i = 0; i <= CONFIG_SYS_MACB_TX_TIMEOUT; i++) {
+ barrier();
+ ctrl = macb->tx_ring[tx_head].ctrl;
+ if (ctrl & TXBUF_USED)
+ break;
+ udelay(1);
+ }
+
+ dma_unmap_single(packet, length, paddr);
+
+ if (i <= CONFIG_SYS_MACB_TX_TIMEOUT) {
+ if (ctrl & TXBUF_UNDERRUN)
+ printf("%s: TX underrun\n", netdev->name);
+ } else {
+ printf("%s: TX timeout\n", netdev->name);
+ }
+
+ /* No one cares anyway */
+ return 0;
+}
+
+static void reclaim_rx_buffers(struct macb_device *macb,
+ unsigned int new_tail)
+{
+ unsigned int i;
+
+ i = macb->rx_tail;
+ while (i > new_tail) {
+ macb->rx_ring[i].addr &= ~RXADDR_USED;
+ i++;
+ if (i > CONFIG_SYS_MACB_RX_RING_SIZE)
+ i = 0;
+ }
+
+ while (i < new_tail) {
+ macb->rx_ring[i].addr &= ~RXADDR_USED;
+ i++;
+ }
+
+ barrier();
+ macb->rx_tail = new_tail;
+}
+
+static int macb_recv(struct eth_device *netdev)
+{
+ struct macb_device *macb = to_macb(netdev);
+ unsigned int rx_tail = macb->rx_tail;
+ void *buffer;
+ int length;
+ int wrapped = 0;
+ u32 status;
+
+ for (;;) {
+ if (!(macb->rx_ring[rx_tail].addr & RXADDR_USED))
+ return -1;
+
+ status = macb->rx_ring[rx_tail].ctrl;
+ if (status & RXBUF_FRAME_START) {
+ if (rx_tail != macb->rx_tail)
+ reclaim_rx_buffers(macb, rx_tail);
+ wrapped = 0;
+ }
+
+ if (status & RXBUF_FRAME_END) {
+ buffer = macb->rx_buffer + 128 * macb->rx_tail;
+ length = status & RXBUF_FRMLEN_MASK;
+ if (wrapped) {
+ unsigned int headlen, taillen;
+
+ headlen = 128 * (CONFIG_SYS_MACB_RX_RING_SIZE
+ - macb->rx_tail);
+ taillen = length - headlen;
+ memcpy((void *)NetRxPackets[0],
+ buffer, headlen);
+ memcpy((void *)NetRxPackets[0] + headlen,
+ macb->rx_buffer, taillen);
+ buffer = (void *)NetRxPackets[0];
+ }
+
+ NetReceive(buffer, length);
+ if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE)
+ rx_tail = 0;
+ reclaim_rx_buffers(macb, rx_tail);
+ } else {
+ if (++rx_tail >= CONFIG_SYS_MACB_RX_RING_SIZE) {
+ wrapped = 1;
+ rx_tail = 0;
+ }
+ }
+ barrier();
+ }
+
+ return 0;
+}
+
+static void macb_phy_reset(struct macb_device *macb)
+{
+ struct eth_device *netdev = &macb->netdev;
+ int i;
+ u16 status, adv;
+
+ adv = ADVERTISE_CSMA | ADVERTISE_ALL;
+ macb_mdio_write(macb, MII_ADVERTISE, adv);
+ printf("%s: Starting autonegotiation...\n", netdev->name);
+ macb_mdio_write(macb, MII_BMCR, (BMCR_ANENABLE
+ | BMCR_ANRESTART));
+
+ for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) {
+ status = macb_mdio_read(macb, MII_BMSR);
+ if (status & BMSR_ANEGCOMPLETE)
+ break;
+ udelay(100);
+ }
+
+ if (status & BMSR_ANEGCOMPLETE)
+ printf("%s: Autonegotiation complete\n", netdev->name);
+ else
+ printf("%s: Autonegotiation timed out (status=0x%04x)\n",
+ netdev->name, status);
+}
+
+#ifdef CONFIG_MACB_SEARCH_PHY
+static int macb_phy_find(struct macb_device *macb)
+{
+ int i;
+ u16 phy_id;
+
+ /* Search for PHY... */
+ for (i = 0; i < 32; i++) {
+ macb->phy_addr = i;
+ phy_id = macb_mdio_read(macb, MII_PHYSID1);
+ if (phy_id != 0xffff) {
+ printf("%s: PHY present at %d\n", macb->netdev.name, i);
+ return 1;
+ }
+ }
+
+ /* PHY isn't up to snuff */
+ printf("%s: PHY not found", macb->netdev.name);
+
+ return 0;
+}
+#endif /* CONFIG_MACB_SEARCH_PHY */
+
+
+static int macb_phy_init(struct macb_device *macb)
+{
+ struct eth_device *netdev = &macb->netdev;
+ u32 ncfgr;
+ u16 phy_id, status, adv, lpa;
+ int media, speed, duplex;
+ int i;
+
+#ifdef CONFIG_MACB_SEARCH_PHY
+ /* Auto-detect phy_addr */
+ if (!macb_phy_find(macb)) {
+ return 0;
+ }
+#endif /* CONFIG_MACB_SEARCH_PHY */
+
+ /* Check if the PHY is up to snuff... */
+ phy_id = macb_mdio_read(macb, MII_PHYSID1);
+ if (phy_id == 0xffff) {
+ printf("%s: No PHY present\n", netdev->name);
+ return 0;
+ }
+
+ /* Timing configuration for KSZ9021RN PHY */
+ macb_mdio_write(macb, 11, 260 | 0x8000);
+ macb_mdio_write(macb, 12, 0xF2F4);
+ macb_mdio_write(macb, 11, 261 | 0x8000);
+ macb_mdio_write(macb, 12, 0x2222);
+
+ status = macb_mdio_read(macb, MII_BMSR);
+ if (!(status & BMSR_LSTATUS)) {
+ /* Try to re-negotiate if we don't have link already. */
+ macb_phy_reset(macb);
+ for (i = 0; i < CONFIG_SYS_MACB_AUTONEG_TIMEOUT / 100; i++) {
+ status = macb_mdio_read(macb, MII_BMSR);
+ if (status & BMSR_LSTATUS)
+ break;
+ udelay(100);
+ }
+ }
+
+ if (!(status & BMSR_LSTATUS)) {
+ printf("%s: link down (status: 0x%04x)\n",
+ netdev->name, status);
+ return 0;
+ } else {
+ /* Judge whether work in 1000Base-T mode */
+ adv = macb_mdio_read(macb, MII_STAT1000);
+ lpa = macb_mdio_read(macb, MII_CTRL1000);
+ if (adv & (1 << 11)) {
+ speed = 1000;
+
+ if (lpa & (1 << 9)) {
+ duplex = 1;
+ } else {
+ duplex = 0;
+ }
+
+ printf("%s: link up, %dMbps %s-duplex (lpa: 0x%04x)\n",
+ netdev->name,
+ speed,
+ duplex ? "full" : "half",
+ lpa);
+
+ ncfgr = macb_readl(macb, NCFGR);
+ ncfgr &= ~(MACB_BIT(GBE) | MACB_BIT (SPD) | MACB_BIT(FD));
+ if (speed)
+ ncfgr |= MACB_BIT(GBE);
+ if (duplex)
+ ncfgr |= MACB_BIT(FD);
+ macb_writel(macb, NCFGR, ncfgr);
+ } else {
+ /* Judge whether work in 100Base-T mode */
+ adv = macb_mdio_read(macb, MII_ADVERTISE);
+ lpa = macb_mdio_read(macb, MII_LPA);
+ media = mii_nway_result(lpa & adv);
+ speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
+ ? 1 : 0);
+ duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+
+ printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n",
+ netdev->name,
+ speed? "100" : "10",
+ duplex ? "full" : "half",
+ lpa);
+
+ ncfgr = macb_readl(macb, NCFGR);
+ ncfgr &= ~(MACB_BIT(GBE) | MACB_BIT(SPD) | MACB_BIT(FD));
+ if (speed)
+ ncfgr |= MACB_BIT(SPD);
+ if (duplex)
+ ncfgr |= MACB_BIT(FD);
+ macb_writel(macb, NCFGR, ncfgr);
+ }
+ }
+
+ return 1;
+}
+
+static int macb_init(struct eth_device *netdev, bd_t *bd)
+{
+ struct macb_device *macb = to_macb(netdev);
+ unsigned long paddr;
+ int i;
+
+ /*
+ * macb_halt should have been called at some point before now,
+ * so we'll assume the controller is idle.
+ */
+
+ /* initialize DMA descriptors */
+ paddr = macb->rx_buffer_dma;
+ for (i = 0; i < CONFIG_SYS_MACB_RX_RING_SIZE; i++) {
+ if (i == (CONFIG_SYS_MACB_RX_RING_SIZE - 1))
+ paddr |= RXADDR_WRAP;
+ macb->rx_ring[i].addr = paddr;
+ macb->rx_ring[i].ctrl = 0;
+ paddr += 128;
+ }
+ for (i = 0; i < CONFIG_SYS_MACB_TX_RING_SIZE; i++) {
+ macb->tx_ring[i].addr = 0;
+ if (i == (CONFIG_SYS_MACB_TX_RING_SIZE - 1))
+ macb->tx_ring[i].ctrl = TXBUF_USED | TXBUF_WRAP;
+ else
+ macb->tx_ring[i].ctrl = TXBUF_USED;
+ }
+ macb->rx_tail = macb->tx_head = macb->tx_tail = 0;
+
+ macb_writel(macb, RBQB, macb->rx_ring_dma);
+ macb_writel(macb, TBQB, macb->tx_ring_dma);
+
+ /* choose RMII or MII mode. This depends on the board */
+#ifdef CONFIG_RGMII
+#if defined(CONFIG_AT91SAMA5)
+ macb_writel(macb, UR, MACB_BIT(RGMII));
+#else
+ macb_writel(macb, UR, 0);
+#endif
+#endif /* CONFIG_RGMII */
+
+ if (!macb_phy_init(macb))
+ return -1;
+
+ /* Enable TX and RX */
+ macb_writel(macb, NCR, MACB_BIT(TE) | MACB_BIT(RE));
+
+ return 0;
+}
+
+static void macb_halt(struct eth_device *netdev)
+{
+ struct macb_device *macb = to_macb(netdev);
+ u32 ncr, tsr;
+
+ /* Halt the controller and wait for any ongoing transmission to end. */
+ ncr = macb_readl(macb, NCR);
+ ncr |= MACB_BIT(THALT);
+ macb_writel(macb, NCR, ncr);
+
+ do {
+ tsr = macb_readl(macb, TSR);
+ } while (tsr & MACB_BIT(TGO));
+
+ /* Disable TX and RX, and clear statistics */
+ macb_writel(macb, NCR, MACB_BIT(CLRSTAT));
+}
+
+static int macb_write_hwaddr(struct eth_device *dev)
+{
+ struct macb_device *macb = to_macb(dev);
+ u32 hwaddr_bottom;
+ u16 hwaddr_top;
+
+ /* set hardware address */
+ hwaddr_bottom = dev->enetaddr[0] | dev->enetaddr[1] << 8 |
+ dev->enetaddr[2] << 16 | dev->enetaddr[3] << 24;
+ macb_writel(macb, SA1B, hwaddr_bottom);
+ hwaddr_top = dev->enetaddr[4] | dev->enetaddr[5] << 8;
+ macb_writel(macb, SA1T, hwaddr_top);
+ return 0;
+}
+
+int gmacb_eth_initialize(int id, void *regs, unsigned int phy_addr)
+{
+ struct macb_device *macb;
+ struct eth_device *netdev;
+ unsigned long macb_hz;
+ u32 ncfgr;
+
+ macb = malloc(sizeof(struct macb_device));
+ if (!macb) {
+ printf("Error: Failed to allocate memory for MACB%d\n", id);
+ return -1;
+ }
+ memset(macb, 0, sizeof(struct macb_device));
+
+ netdev = &macb->netdev;
+
+ macb->rx_buffer = dma_alloc_coherent(CONFIG_SYS_MACB_RX_BUFFER_SIZE,
+ &macb->rx_buffer_dma);
+
+ macb->rx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_RX_RING_SIZE
+ * sizeof(struct macb_dma_desc),
+ &macb->rx_ring_dma);
+ macb->tx_ring = dma_alloc_coherent(CONFIG_SYS_MACB_TX_RING_SIZE
+ * sizeof(struct macb_dma_desc),
+ &macb->tx_ring_dma);
+
+ macb->regs = regs;
+ macb->phy_addr = phy_addr;
+
+ sprintf(netdev->name, "gmacb%d", id);
+ netdev->init = macb_init;
+ netdev->halt = macb_halt;
+ netdev->send = macb_send;
+ netdev->recv = macb_recv;
+ netdev->write_hwaddr = macb_write_hwaddr;
+
+ /*
+ * Do some basic initialization so that we at least can talk
+ * to the PHY
+ */
+ macb_hz = get_macb_pclk_rate(id);
+ if (macb_hz < 20000000)
+ ncfgr = MACB_BF(CLK, GMACB_CLK_DIV8);
+ else if (macb_hz < 40000000)
+ ncfgr = MACB_BF(CLK, GMACB_CLK_DIV16);
+ else if (macb_hz < 80000000)
+ ncfgr = MACB_BF(CLK, GMACB_CLK_DIV32);
+ else if (macb_hz < 120000000)
+ ncfgr = MACB_BF(CLK, GMACB_CLK_DIV48);
+ else
+ ncfgr = MACB_BF(CLK, GMACB_CLK_DIV64);
+
+ macb_writel(macb, NCFGR, ncfgr);
+
+ /* Configuration the Datapath 64 bit */
+ macb_writel(macb, NCFGR, MACB_BF(DBW, 1) | macb_readl(macb, NCFGR));
+
+ eth_register(netdev);
+
+#if defined(CONFIG_CMD_MII)
+ miiphy_register(netdev->name, macb_miiphy_read, macb_miiphy_write);
+#endif
+ return 0;
+}
+
+#endif
diff --git a/drivers/net/gmacb.h b/drivers/net/gmacb.h
new file mode 100644
index 0000000000..cd755bccc3
--- /dev/null
+++ b/drivers/net/gmacb.h
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2005-2006 Atmel Corporation
+ *
+ * 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
+ */
+#ifndef __DRIVERS_GMACB_H__
+#define __DRIVERS_GMACB_H__
+
+/* MACB register offsets */
+#define GMACB_NCR 0x0000
+#define GMACB_NCFGR 0x0004
+#define GMACB_NSR 0x0008
+#define GMACB_UR 0x000c
+#define GMACB_DCFGR 0x0010
+#define GMACB_TSR 0x0014
+#define GMACB_RBQB 0x0018
+#define GMACB_TBQB 0x001c
+#define GMACB_RSR 0x0020
+#define GMACB_ISR 0x0024
+#define GMACB_IER 0x0028
+#define GMACB_IDR 0x002c
+#define GMACB_IMR 0x0030
+#define GMACB_MAN 0x0034
+#define GMACB_RPQ 0x0038
+#define GMACB_TPQ 0x003c
+#define GMACB_TPSF 0x0040
+#define GMACB_RPSF 0x0044
+#define GMACB_HRB 0x0080
+#define GMACB_HRT 0x0084
+#define GMACB_SA1B 0x0088
+#define GMACB_SA1T 0x008c
+#define GMACB_SA2B 0x0090
+#define GMACB_SA2T 0x0094
+#define GMACB_SA3B 0x0098
+#define GMACB_SA3T 0x009c
+#define GMACB_SA4B 0x00a0
+#define GMACB_SA4T 0x00a4
+#define GMACB_TIDM1 0x00a8
+#define GMACB_TIDM2 0x00ac
+#define GMACB_TIDM3 0x00b0
+#define GMACB_TIDM4 0x00b4
+#define GMACB_WOL 0x00b8
+#define GMACB_IPGS 0x00bc
+#define GMACB_SVLAN 0x00c0
+#define GMACB_TPFCP 0x00c4
+#define GMACB_SAMB1 0x00c8
+#define GMACB_SAMT1 0x00cc
+
+#define GMACB_FT 0x0108
+#define GMACB_BCFT 0x010c
+
+
+
+
+ /* Bitfields in NCR */
+#define GMACB_LB_OFFSET 0
+#define GMACB_LB_SIZE 1
+#define GMACB_LBL_OFFSET 1
+#define GMACB_LBL_SIZE 1
+#define GMACB_RE_OFFSET 2
+#define GMACB_RE_SIZE 1
+#define GMACB_TE_OFFSET 3
+#define GMACB_TE_SIZE 1
+#define GMACB_MPE_OFFSET 4
+#define GMACB_MPE_SIZE 1
+#define GMACB_CLRSTAT_OFFSET 5
+#define GMACB_CLRSTAT_SIZE 1
+#define GMACB_INCSTAT_OFFSET 6
+#define GMACB_INCSTAT_SIZE 1
+#define GMACB_WESTAT_OFFSET 7
+#define GMACB_WESTAT_SIZE 1
+#define GMACB_BP_OFFSET 8
+#define GMACB_BP_SIZE 1
+#define GMACB_TSTART_OFFSET 9
+#define GMACB_TSTART_SIZE 1
+#define GMACB_THALT_OFFSET 10
+#define GMACB_THALT_SIZE 1
+#define GMACB_NCR_TPF_OFFSET 11
+#define GMACB_NCR_TPF_SIZE 1
+#define GMACB_TZQ_OFFSET 12
+#define GMACB_TZQ_SIZE 1
+
+ /* Bitfields in NCFGR */
+#define GMACB_SPD_OFFSET 0
+#define GMACB_SPD_SIZE 1
+#define GMACB_FD_OFFSET 1
+#define GMACB_FD_SIZE 1
+#define GMACB_DNVLAN_OFFSET 2
+#define GMACB_DNVLAN_SIZE 1
+#define GMACB_JFRAME_OFFSET 3
+#define GMACB_JFRAME_SIZE 1
+#define GMACB_CAF_OFFSET 4
+#define GMACB_CAF_SIZE 1
+#define GMACB_NBC_OFFSET 5
+#define GMACB_NBC_SIZE 1
+#define GMACB_NCFGR_MTI_OFFSET 6
+#define GMACB_NCFGR_MTI_SIZE 1
+#define GMACB_UNI_OFFSET 7
+#define GMACB_UNI_SIZE 1
+#define MACB_MAXFS_OFFSET 8
+#define MACB_MAXFS_SIZE 1
+#define GMACB_GBE_OFFSET 10
+#define GMACB_GBE_SIZE 1
+#define GMACB_PIS_OFFSET 11
+#define GMACB_PIS_SIZE 1
+#define GMACB_RTY_OFFSET 12
+#define GMACB_RTY_SIZE 1
+#define GMACB_PEN_OFFSET 13
+#define GMACB_PEN_SIZE 1
+#define GMACB_RXBUFO_OFFSET 14
+#define GMACB_RXBUFO_SIZE 2
+#define GMACB_LFERD_OFFSET 16
+#define GMACB_LFERD_SIZE 1
+#define GMACB_RFCS_OFFSET 17
+#define GMACB_RFCS_SIZE 1
+#define GMACB_CLK_OFFSET 18
+#define GMACB_CLK_SIZE 3
+#define GMACB_DBW_OFFSET 21
+#define GMACB_DBW_SIZE 2
+
+ /* Bitfields in NSR */
+#define GMACB_NSR_LINK_OFFSET 0
+#define GMACB_NSR_LINK_SIZE 1
+#define GMACB_MDIO_OFFSET 1
+#define GMACB_MDIO_SIZE 1
+#define GMACB_IDLE_OFFSET 2
+#define GMACB_IDLE_SIZE 1
+
+ /* Bitfields in TSR */
+#define GMACB_UBR_OFFSET 0
+#define GMACB_UBR_SIZE 1
+#define GMACB_COL_OFFSET 1
+#define GMACB_COL_SIZE 1
+#define GMACB_TSR_RLE_OFFSET 2
+#define GMACB_TSR_RLE_SIZE 1
+#define GMACB_TGO_OFFSET 3
+#define GMACB_TGO_SIZE 1
+#define GMACB_BEX_OFFSET 4
+#define GMACB_BEX_SIZE 1
+#define GMACB_COMP_OFFSET 5
+#define GMACB_COMP_SIZE 1
+#define GMACB_UND_OFFSET 6
+#define GMACB_UND_SIZE 1
+
+ /* Bitfields in RSR */
+#define GMACB_BNA_OFFSET 0
+#define GMACB_BNA_SIZE 1
+#define GMACB_REC_OFFSET 1
+#define GMACB_REC_SIZE 1
+#define GMACB_OVR_OFFSET 2
+#define GMACB_OVR_SIZE 1
+
+ /* Bitfields in ISR/IER/IDR/IMR */
+#define GMACB_MFD_OFFSET 0
+#define GMACB_MFD_SIZE 1
+#define GMACB_RCOMP_OFFSET 1
+#define GMACB_RCOMP_SIZE 1
+#define GMACB_RXUBR_OFFSET 2
+#define GMACB_RXUBR_SIZE 1
+#define GMACB_TXUBR_OFFSET 3
+#define GMACB_TXUBR_SIZE 1
+#define GMACB_ISR_TUND_OFFSET 4
+#define GMACB_ISR_TUND_SIZE 1
+#define GMACB_ISR_RLE_OFFSET 5
+#define GMACB_ISR_RLE_SIZE 1
+#define GMACB_TXERR_OFFSET 6
+#define GMACB_TXERR_SIZE 1
+#define GMACB_TCOMP_OFFSET 7
+#define GMACB_TCOMP_SIZE 1
+#define GMACB_ISR_LINK_OFFSET 9
+#define GMACB_ISR_LINK_SIZE 1
+#define GMACB_ISR_ROVR_OFFSET 10
+#define GMACB_ISR_ROVR_SIZE 1
+#define GMACB_HRESP_OFFSET 11
+#define GMACB_HRESP_SIZE 1
+#define GMACB_PFR_OFFSET 12
+#define GMACB_PFR_SIZE 1
+#define GMACB_PTZ_OFFSET 13
+#define GMACB_PTZ_SIZE 1
+
+ /* Bitfields in MAN */
+#define GMACB_DATA_OFFSET 0
+#define GMACB_DATA_SIZE 16
+#define GMACB_WTN_OFFSET 16
+#define GMACB_WTN_SIZE 2
+#define GMACB_REGA_OFFSET 18
+#define GMACB_REGA_SIZE 5
+#define GMACB_PHYA_OFFSET 23
+#define GMACB_PHYA_SIZE 5
+#define GMACB_OP_OFFSET 28
+#define GMACB_OP_SIZE 2
+#define GMACB_CLTTO_OFFSET 30
+#define GMACB_CLTTO_SIZE 1
+#define GMACB_WZO_OFFSET 31
+#define GMACB_WZO_SIZE 1
+
+ /* Bitfields in US */
+#define GMACB_GMII_OFFSET 0
+#define GMACB_GMII_SIZE 1
+
+ /* Bitfields in USRIO (AT91) */
+#define GMACB_RGMII_OFFSET 0
+#define GMACB_RGMII_SIZE 1
+
+ /* Bitfields in WOL */
+#define GMACB_IP_OFFSET 0
+#define GMACB_IP_SIZE 16
+#define GMACB_MAG_OFFSET 16
+#define GMACB_MAG_SIZE 1
+#define GMACB_ARP_OFFSET 17
+#define GMACB_ARP_SIZE 1
+#define GMACB_SA1_OFFSET 18
+#define GMACB_SA1_SIZE 1
+#define GMACB_WOL_MTI_OFFSET 19
+#define GMACB_WOL_MTI_SIZE 1
+
+ /* Constants for CLK */
+#define GMACB_CLK_DIV8 0
+#define GMACB_CLK_DIV16 1
+#define GMACB_CLK_DIV32 2
+#define GMACB_CLK_DIV48 3
+#define GMACB_CLK_DIV64 4
+
+/* Constants for MAN register */
+#define GMACB_MAN_SOF 1
+#define GMACB_MAN_WRITE 1
+#define GMACB_MAN_READ 2
+#define GMACB_MAN_CODE 2
+
+/* Bit manipulation macros */
+#define MACB_BIT(name) \
+ (1 << GMACB_##name##_OFFSET)
+#define MACB_BF(name,value) \
+ (((value) & ((1 << GMACB_##name##_SIZE) - 1)) \
+ << GMACB_##name##_OFFSET)
+#define MACB_BFEXT(name,value)\
+ (((value) >> GMACB_##name##_OFFSET) \
+ & ((1 << GMACB_##name##_SIZE) - 1))
+#define MACB_BFINS(name,value,old) \
+ (((old) & ~(((1 << GMACB_##name##_SIZE) - 1) \
+ << GMACB_##name##_OFFSET)) \
+ | MACB_BF(name,value))
+
+/* Register access macros */
+#define macb_readl(port,reg) \
+ readl((port)->regs + GMACB_##reg)
+#define macb_writel(port,reg,value) \
+ writel((value), (port)->regs + GMACB_##reg)
+
+#endif /* __DRIVERS_MACB_H__ */
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 0e1ced71c5..f05a566521 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -471,7 +471,8 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)
#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \
defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20) || \
defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \
- defined(CONFIG_AT91SAM9XE) || defined(CONFIG_AT91SAM9X5)
+ defined(CONFIG_AT91SAM9XE) || defined(CONFIG_AT91SAM9X5) || \
+ defined(CONFIG_AT91SAMA5)
macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN));
#else
macb_writel(macb, USRIO, 0);
@@ -480,7 +481,8 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)
#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \
defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20) || \
defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \
- defined(CONFIG_AT91SAM9XE) || defined(CONFIG_AT91SAM9X5)
+ defined(CONFIG_AT91SAM9XE) || defined(CONFIG_AT91SAM9X5) || \
+ defined(CONFIG_AT91SAMA5)
macb_writel(macb, USRIO, MACB_BIT(CLKEN));
#else
macb_writel(macb, USRIO, MACB_BIT(MII));
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 9532dd9ef6..48de03d36b 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -41,7 +41,8 @@ int usb_cpu_init(void)
writel(get_pllb_init(), &pmc->pllbr);
while ((readl(&pmc->sr) & AT91_PMC_LOCKB) != AT91_PMC_LOCKB)
;
-#elif defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45)
+#elif defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) \
+ || defined(CONFIG_AT91SAMA5)
/* Enable UPLL */
writel(readl(&pmc->uckr) | AT91_PMC_UPLLEN | AT91_PMC_BIASEN,
&pmc->uckr);
@@ -52,8 +53,13 @@ int usb_cpu_init(void)
writel(AT91_PMC_USBS_USB_UPLL | AT91_PMC_USBDIV_10, &pmc->usb);
#endif
+#if defined(CONFIG_AT91SAMA5)
/* Enable USB host clock. */
+ writel(1 << (ATMEL_ID_UHP - 32), &pmc->pcer1);
+#else
writel(1 << ATMEL_ID_UHP, &pmc->pcer);
+#endif
+
#ifdef CONFIG_AT91SAM9261
writel(ATMEL_PMC_UHP | AT91_PMC_HCK0, &pmc->scer);
#else
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index c02ffd8036..860cbcc4d2 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -28,6 +28,9 @@
#include <asm/arch/clk.h>
#include <lcd.h>
#include <atmel_lcdc.h>
+#if defined(CONFIG_AT91SAM9X5) || defined(CONFIG_AT91SAMA5)
+#include <atmel_9x5_lcdc.h>
+#endif
int lcd_line_length;
int lcd_color_fg;
@@ -66,10 +69,187 @@ void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
#endif
}
+#if defined(CONFIG_AT91SAM9X5) || defined(CONFIG_AT91SAMA5)
+void lcd_9x5_ctrl_init(void *lcdbase)
+{
+ unsigned long value;
+ lcd_dma_desc *desc;
+
+ if (!has_lcdc())
+ return; /* No lcdc */
+
+ /* Disable DISP signal */
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS);
+ while ((lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_DISPSTS))
+ udelay(1);
+ /* Disable synchronization */
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS);
+ while ((lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_LCDSTS))
+ udelay(1);
+ /* Disable pixel clock */
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS);
+ while ((lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_CLKSTS))
+ udelay(1);
+ /* Disable PWM */
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS);
+ while ((lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_PWMSTS))
+ udelay(1);
+
+ /* Set pixel clock */
+ value = get_lcdc_clk_rate(0) / panel_info.vl_clk;
+ if (get_lcdc_clk_rate(0) % panel_info.vl_clk)
+ value++;
+
+ if (value < 1) {
+ /* Using system clock as pixel clock */
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCFG0,
+ LCDC_LCDCFG0_CLKDIV(0)
+ | LCDC_LCDCFG0_CGDISHCR
+ | LCDC_LCDCFG0_CGDISHEO
+ | LCDC_LCDCFG0_CGDISOVR1
+ | LCDC_LCDCFG0_CGDISBASE
+ | LCDC_LCDCFG0_CLKPOL
+ | LCDC_LCDCFG0_CLKSEL);
+
+ } else {
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCFG0,
+ LCDC_LCDCFG0_CLKDIV(value - 2)
+ | LCDC_LCDCFG0_CGDISHCR
+ | LCDC_LCDCFG0_CGDISHEO
+ | LCDC_LCDCFG0_CGDISOVR1
+ | LCDC_LCDCFG0_CGDISBASE
+ | LCDC_LCDCFG0_CLKPOL);
+ }
+
+ /* Initialize control register 5 */
+ value = 0;
+
+ value |= LCDC_LCDCFG5_HSPOL;
+ value |= LCDC_LCDCFG5_VSPOL;
+
+#ifndef LCD_OUTPUT_BPP
+ /* Output is 24bpp */
+ value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
+#else
+ switch (LCD_OUTPUT_BPP) {
+ case 12:
+ value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
+ break;
+ case 16:
+ value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP;
+ break;
+ case 18:
+ value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP;
+ break;
+ case 24:
+ value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
+ break;
+ default:
+ BUG();
+ break;
+ }
+#endif
+
+ value |= LCDC_LCDCFG5_GUARDTIME(ATMEL_LCDC_GUARD_TIME);
+ value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS);
+
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCFG5, value);
+
+ /* Vertical & Horizontal Timing */
+ value = LCDC_LCDCFG1_VSPW(panel_info.vl_vsync_len - 1);
+ value |= LCDC_LCDCFG1_HSPW(panel_info.vl_hsync_len - 1);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCFG1, value);
+
+ value = LCDC_LCDCFG2_VBPW(panel_info.vl_lower_margin);
+ value |= LCDC_LCDCFG2_VFPW(panel_info.vl_upper_margin - 1);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCFG2, value);
+
+ value = LCDC_LCDCFG3_HBPW(panel_info.vl_right_margin - 1);
+ value |= LCDC_LCDCFG3_HFPW(panel_info.vl_left_margin - 1);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCFG3, value);
+
+ /* Display size */
+ value = LCDC_LCDCFG4_RPF(panel_info.vl_row - 1);
+ value |= LCDC_LCDCFG4_PPL(panel_info.vl_col - 1);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCFG4, value);
+
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASECFG0,
+ LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);
+
+ switch (NBITS(panel_info.vl_bpix)) {
+ case 16:
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASECFG1,
+ LCDC_BASECFG1_RGBMODE_16BPP_RGB_565);
+ break;
+ default:
+ BUG();
+ break;
+ }
+
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASECFG2,
+ LCDC_BASECFG2_XSTRIDE(0));
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASECFG3, 0);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASECFG4, LCDC_BASECFG4_DMA);
+
+ /* Disable all interrupts */
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDIDR, ~0UL);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASEIDR, ~0UL);
+
+ /* Setup the DMA descriptor, this descriptor will loop to itself */
+ desc = (lcd_dma_desc *)(lcdbase - 16);
+
+ desc->address = (u32)lcdbase;
+ /* Disable DMA transfer interrupt & descriptor loaded interrupt. */
+ desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
+ | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
+ desc->next = (u32)desc;
+
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASEADDR, desc->address);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASECTRL, desc->control);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASENEXT, desc->next);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN
+ | LCDC_BASECHER_UPDATEEN);
+
+ /* Enable LCD */
+ value = lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDEN);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDEN, value
+ | LCDC_LCDEN_CLKEN);
+ while (!(lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_CLKSTS))
+ udelay(1);
+ value = lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDEN);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDEN, value
+ | LCDC_LCDEN_SYNCEN);
+ while (!(lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_LCDSTS))
+ udelay(1);
+ value = lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDEN);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDEN, value
+ | LCDC_LCDEN_DISPEN);
+ while (!(lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_DISPSTS))
+ udelay(1);
+ value = lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDEN);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDEN, value
+ | LCDC_LCDEN_PWMEN);
+ while (!(lcdc_readl(panel_info.mmio, ATMEL_LCDC_LCDSR)
+ & LCDC_LCDSR_PWMSTS))
+ udelay(1);
+}
+#endif
+
void lcd_ctrl_init(void *lcdbase)
{
unsigned long value;
+#if defined(CONFIG_AT91SAM9X5) || defined(CONFIG_AT91SAMA5)
+ return lcd_9x5_ctrl_init(lcdbase);
+#endif
+
/* Turn off the LCD controller and the DMA controller */
lcdc_writel(panel_info.mmio, ATMEL_LCDC_PWRCON,
ATMEL_LCDC_GUARD_TIME << ATMEL_LCDC_GUARDT_OFFSET);
@@ -96,7 +276,8 @@ void lcd_ctrl_init(void *lcdbase)
value = (value / 2) - 1;
if (!value) {
- lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON1,
+ ATMEL_LCDC_BYPASS);
} else
lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON1,
value << ATMEL_LCDC_CLKVAL_OFFSET);
@@ -143,18 +324,19 @@ void lcd_ctrl_init(void *lcdbase)
/* Set contrast */
value = ATMEL_LCDC_PS_DIV8 |
+ ATMEL_LCDC_POL_POSITIVE |
ATMEL_LCDC_ENA_PWMENABLE;
- if (!panel_info.vl_cont_pol_low)
- value |= ATMEL_LCDC_POL_POSITIVE;
lcdc_writel(panel_info.mmio, ATMEL_LCDC_CONTRAST_CTR, value);
- lcdc_writel(panel_info.mmio, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+ lcdc_writel(panel_info.mmio, ATMEL_LCDC_CONTRAST_VAL,
+ ATMEL_LCDC_CVAL_DEFAULT);
/* Set framebuffer DMA base address and pixel offset */
lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMABADDR1, (u_long)lcdbase);
lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMACON, ATMEL_LCDC_DMAEN);
lcdc_writel(panel_info.mmio, ATMEL_LCDC_PWRCON,
- (ATMEL_LCDC_GUARD_TIME << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
+ (ATMEL_LCDC_GUARD_TIME << ATMEL_LCDC_GUARDT_OFFSET)
+ | ATMEL_LCDC_PWR);
}
ulong calc_fbsize(void)