diff options
Diffstat (limited to 'drivers')
63 files changed, 5744 insertions, 2093 deletions
diff --git a/drivers/bios_emulator/Makefile b/drivers/bios_emulator/Makefile index c73da97..dd9c102 100644 --- a/drivers/bios_emulator/Makefile +++ b/drivers/bios_emulator/Makefile @@ -22,7 +22,7 @@ EXTRA_CFLAGS += -I. -I./include -I$(TOPDIR)/include \ -D__PPC__ -D__BIG_ENDIAN__ CFLAGS += $(EXTRA_CFLAGS) -HOST_CFLAGS += $(EXTRA_CFLAGS) +HOSTCFLAGS += $(EXTRA_CFLAGS) all: $(LIB) diff --git a/drivers/bios_emulator/atibios.c b/drivers/bios_emulator/atibios.c index d950b18..5f9bd10 100644 --- a/drivers/bios_emulator/atibios.c +++ b/drivers/bios_emulator/atibios.c @@ -3,7 +3,7 @@ * Video BOOT Graphics Card POST Module * * ======================================================================== -* Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +* Copyright (C) 2007 Freescale Semiconductor, Inc. * Jason Jin <Jason.jin@freescale.com> * * Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved. diff --git a/drivers/bios_emulator/besys.c b/drivers/bios_emulator/besys.c index cbc5062..84724b7 100644 --- a/drivers/bios_emulator/besys.c +++ b/drivers/bios_emulator/besys.c @@ -5,7 +5,7 @@ * * ======================================================================== * -* Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +* Copyright (C) 2007 Freescale Semiconductor, Inc. * Jason Jin<Jason.jin@freescale.com> * * Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved. diff --git a/drivers/bios_emulator/bios.c b/drivers/bios_emulator/bios.c index edda276..7cf4879 100644 --- a/drivers/bios_emulator/bios.c +++ b/drivers/bios_emulator/bios.c @@ -3,7 +3,7 @@ * BIOS emulator and interface * to Realmode X86 Emulator Library * -* Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +* Copyright (C) 2007 Freescale Semiconductor, Inc. * Jason Jin <Jason.jin@freescale.com> * * Copyright (C) 1996-1999 SciTech Software, Inc. diff --git a/drivers/bios_emulator/biosemu.c b/drivers/bios_emulator/biosemu.c index d0c6521..9d4f07c 100644 --- a/drivers/bios_emulator/biosemu.c +++ b/drivers/bios_emulator/biosemu.c @@ -3,7 +3,7 @@ * BIOS emulator and interface * to Realmode X86 Emulator Library * -* Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +* Copyright (C) 2007 Freescale Semiconductor, Inc. * Jason Jin <Jason.jin@freescale.com> * * Copyright (C) 1996-1999 SciTech Software, Inc. @@ -144,7 +144,8 @@ void X86API BE_setVGA(BE_VGAInfo * info) _BE_env.biosmem_base = _BE_env.busmem_base + 0x20000; _BE_env.biosmem_limit = 0xC7FFF; } - if (*((u32 *) info->LowMem) == 0) + if ((info->LowMem[0] == 0) && (info->LowMem[1] == 0) && + (info->LowMem[2] == 0) && (info->LowMem[3] == 0)) _BE_bios_init((u32 *) info->LowMem); memcpy((u8 *) M.mem_base, info->LowMem, sizeof(info->LowMem)); } diff --git a/drivers/bios_emulator/biosemui.h b/drivers/bios_emulator/biosemui.h index e85e656..8c1f111 100644 --- a/drivers/bios_emulator/biosemui.h +++ b/drivers/bios_emulator/biosemui.h @@ -3,7 +3,7 @@ * BIOS emulator and interface * to Realmode X86 Emulator Library * -* Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +* Copyright (C) 2007 Freescale Semiconductor, Inc. * Jason Jin <Jason.jin@freescale.com> * * Copyright (C) 1996-1999 SciTech Software, Inc. diff --git a/drivers/bios_emulator/x86emu/ops.c b/drivers/bios_emulator/x86emu/ops.c index d63c99f..f884e9b 100644 --- a/drivers/bios_emulator/x86emu/ops.c +++ b/drivers/bios_emulator/x86emu/ops.c @@ -1,7 +1,7 @@ /**************************************************************************** * Realmode X86 Emulator Library * -* Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +* Copyright (C) 2007 Freescale Semiconductor, Inc. * Jason Jin <Jason.jin@freescale.com> * * Copyright (C) 1991-2004 SciTech Software, Inc. diff --git a/drivers/bios_emulator/x86emu/ops2.c b/drivers/bios_emulator/x86emu/ops2.c index 51e20e1..ee7258e 100644 --- a/drivers/bios_emulator/x86emu/ops2.c +++ b/drivers/bios_emulator/x86emu/ops2.c @@ -2,7 +2,7 @@ * * Realmode X86 Emulator Library * -* Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. +* Copyright (C) 2007 Freescale Semiconductor, Inc. * Jason Jin <Jason.jin@freescale.com> * * Copyright (C) 1991-2004 SciTech Software, Inc. diff --git a/drivers/block/Makefile b/drivers/block/Makefile index eccefc1..3f6ad5c 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -31,6 +31,7 @@ COBJS-$(CONFIG_FSL_SATA) += fsl_sata.o COBJS-$(CONFIG_IDE_SIL680) += sil680.o COBJS-$(CONFIG_LIBATA) += libata.o COBJS-$(CONFIG_PATA_BFIN) += pata_bfin.o +COBJS-$(CONFIG_SATA_DWC) += sata_dwc.o COBJS-$(CONFIG_SATA_SIL3114) += sata_sil3114.o COBJS-$(CONFIG_SCSI_AHCI) += ahci.o COBJS-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index e1b66fd..a3ca2dc 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -1,5 +1,5 @@ /* - * Copyright (C) Freescale Semiconductor, Inc. 2006. All rights reserved. + * Copyright (C) Freescale Semiconductor, Inc. 2006. * Author: Jason Jin<Jason.jin@freescale.com> * Zhang Wei<wei.zhang@freescale.com> * @@ -602,7 +602,7 @@ static int ata_scsiop_read10(ccb * pccb) */ static int ata_scsiop_read_capacity10(ccb *pccb) { - u8 buf[8]; + u32 cap; if (!ataid[pccb->target]) { printf("scsi_ahci: SCSI READ CAPACITY10 command failure. " @@ -611,14 +611,12 @@ static int ata_scsiop_read_capacity10(ccb *pccb) return -EPERM; } - memset(buf, 0, 8); + cap = le32_to_cpu(ataid[pccb->target]->lba_capacity); + memcpy(pccb->pdata, &cap, sizeof(cap)); - *(u32 *) buf = le32_to_cpu(ataid[pccb->target]->lba_capacity); - - buf[6] = 512 >> 8; - buf[7] = 512 & 0xff; - - memcpy(pccb->pdata, buf, 8); + pccb->pdata[4] = pccb->pdata[5] = 0; + pccb->pdata[6] = 512 >> 8; + pccb->pdata[7] = 512 & 0xff; return 0; } diff --git a/drivers/block/ata_piix.c b/drivers/block/ata_piix.c index ec37687..549de31 100644 --- a/drivers/block/ata_piix.c +++ b/drivers/block/ata_piix.c @@ -36,7 +36,7 @@ #include <ata.h> extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; -extern int curr_device; +extern int sata_curr_device; #define DEBUG_SATA 0 /*For debug prints set DEBUG_SATA to 1 */ @@ -204,8 +204,8 @@ init_sata (int dev) dev_print (&sata_dev_desc[devno]); /* initialize partition type */ init_part (&sata_dev_desc[devno]); - if (curr_device < 0) - curr_device = + if (sata_curr_device < 0) + sata_curr_device = i * CONFIG_SYS_SATA_DEVS_PER_BUS + j; } } diff --git a/drivers/block/fsl_sata.c b/drivers/block/fsl_sata.c index 2009d1e..abcda6f 100644 --- a/drivers/block/fsl_sata.c +++ b/drivers/block/fsl_sata.c @@ -81,7 +81,7 @@ void dprint_buffer(unsigned char *buf, int len) printf("\n\r"); } -static void fsl_sata_dump_sfis(struct sfis *s) +static void fsl_sata_dump_sfis(struct sata_fis_d2h *s) { printf("Status FIS dump:\n\r"); printf("fis_type: %02x\n\r", s->fis_type); @@ -347,7 +347,7 @@ static void fsl_sata_dump_regs(fsl_sata_reg_t *reg) printf("SYSPR: %08x\n\r", in_be32(®->syspr)); } -static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct cfis *cfis, +static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, int is_ncq, int tag, u8 *buffer, u32 len) { cmd_hdr_entry_t *cmd_hdr; @@ -483,7 +483,7 @@ static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct cfis *cfis, if (val32) { u32 der; - fsl_sata_dump_sfis((struct sfis *)cmd_desc->sfis); + fsl_sata_dump_sfis((struct sata_fis_d2h *)cmd_desc->sfis); printf("CE at device\n\r"); fsl_sata_dump_regs(reg); der = in_le32(®->der); @@ -498,13 +498,13 @@ static int fsl_ata_exec_ata_cmd(struct fsl_sata *sata, struct cfis *cfis, return len; } -static int fsl_ata_exec_reset_cmd(struct fsl_sata *sata, struct cfis *cfis, +static int fsl_ata_exec_reset_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, int tag, u8 *buffer, u32 len) { return 0; } -static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct cfis *cfis, +static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, enum cmd_type command_type, int tag, u8 *buffer, u32 len) { int rc; @@ -539,11 +539,9 @@ static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct cfis *cfis, static void fsl_sata_identify(int dev, u16 *id) { fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d; - struct cfis *cfis; + struct sata_fis_h2d h2d, *cfis = &h2d; - cfis = (struct cfis *)&h2d; - memset((void *)cfis, 0, sizeof(struct cfis)); + memset(cfis, 0, sizeof(struct sata_fis_h2d)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; cfis->pm_port_c = 0x80; /* is command */ @@ -566,12 +564,10 @@ static void fsl_sata_xfer_mode(int dev, u16 *id) static void fsl_sata_set_features(int dev) { fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d; - struct cfis *cfis; + struct sata_fis_h2d h2d, *cfis = &h2d; u8 udma_cap; - cfis = (struct cfis *)&h2d; - memset((void *)cfis, 0, sizeof(struct cfis)); + memset(cfis, 0, sizeof(struct sata_fis_h2d)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; cfis->pm_port_c = 0x80; /* is command */ @@ -597,14 +593,12 @@ static void fsl_sata_set_features(int dev) static u32 fsl_sata_rw_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) { fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d; - struct cfis *cfis; + struct sata_fis_h2d h2d, *cfis = &h2d; u32 block; block = start; - cfis = (struct cfis *)&h2d; - memset((void *)cfis, 0, sizeof(struct cfis)); + memset(cfis, 0, sizeof(struct sata_fis_h2d)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; cfis->pm_port_c = 0x80; /* is command */ @@ -624,12 +618,9 @@ static u32 fsl_sata_rw_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_wr void fsl_sata_flush_cache(int dev) { fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d; - struct cfis *cfis; + struct sata_fis_h2d h2d, *cfis = &h2d; - cfis = (struct cfis *)&h2d; - - memset((void *)cfis, 0, sizeof(struct cfis)); + memset(cfis, 0, sizeof(struct sata_fis_h2d)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; cfis->pm_port_c = 0x80; /* is command */ @@ -641,14 +632,12 @@ void fsl_sata_flush_cache(int dev) static u32 fsl_sata_rw_cmd_ext(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) { fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d; - struct cfis *cfis; + struct sata_fis_h2d h2d, *cfis = &h2d; u64 block; block = (u64)start; - cfis = (struct cfis *)&h2d; - memset((void *)cfis, 0, sizeof(struct cfis)); + memset(cfis, 0, sizeof(struct sata_fis_h2d)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; cfis->pm_port_c = 0x80; /* is command */ @@ -673,8 +662,7 @@ static u32 fsl_sata_rw_cmd_ext(int dev, u32 start, u32 blkcnt, u8 *buffer, int i u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) { fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d; - struct cfis *cfis; + struct sata_fis_h2d h2d, *cfis = &h2d; int ncq_channel; u64 block; @@ -684,9 +672,8 @@ u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write } block = (u64)start; - cfis = (struct cfis *)&h2d; - memset((void *)cfis, 0, sizeof(struct cfis)); + memset(cfis, 0, sizeof(struct sata_fis_h2d)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; cfis->pm_port_c = 0x80; /* is command */ @@ -718,12 +705,9 @@ u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write void fsl_sata_flush_cache_ext(int dev) { fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d; - struct cfis *cfis; - - cfis = (struct cfis *)&h2d; + struct sata_fis_h2d h2d, *cfis = &h2d; - memset((void *)cfis, 0, sizeof(struct cfis)); + memset(cfis, 0, sizeof(struct sata_fis_h2d)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; cfis->pm_port_c = 0x80; /* is command */ diff --git a/drivers/block/fsl_sata.h b/drivers/block/fsl_sata.h index 874c0dc..18e88fa 100644 --- a/drivers/block/fsl_sata.h +++ b/drivers/block/fsl_sata.h @@ -289,52 +289,6 @@ typedef struct cmd_desc { #define SATA_HC_CMD_DESC_ALIGN 4 /* -* CFIS - Command FIS, which is H2D register FIS, the struct defination -* of Non-Queued command is different than NCQ command. see them is sata2.h -*/ -typedef struct cfis { - u8 fis_type; - u8 pm_port_c; - u8 command; - u8 features; - u8 lba_low; - u8 lba_mid; - u8 lba_high; - u8 device; - u8 lba_low_exp; - u8 lba_mid_exp; - u8 lba_high_exp; - u8 features_exp; - u8 sector_count; - u8 sector_count_exp; - u8 res1; - u8 control; - u8 res2[4]; -} __attribute__ ((packed)) cfis_t; - -/* -* SFIS - Status FIS, which is D2H register FIS. -*/ -typedef struct sfis { - u8 fis_type; - u8 pm_port_i; - u8 status; - u8 error; - u8 lba_low; - u8 lba_mid; - u8 lba_high; - u8 device; - u8 lba_low_exp; - u8 lba_mid_exp; - u8 lba_high_exp; - u8 res1; - u8 sector_count; - u8 sector_count_exp; - u8 res2[2]; - u8 res3[4]; -} __attribute__ ((packed)) sfis_t; - -/* * SATA device driver info */ typedef struct fsl_sata_info { diff --git a/drivers/block/sata_dwc.c b/drivers/block/sata_dwc.c new file mode 100644 index 0000000..b2b3804 --- /dev/null +++ b/drivers/block/sata_dwc.c @@ -0,0 +1,2110 @@ +/* + * sata_dwc.c + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld <mmiesfeld@amcc.com> + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr@denx.de> + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * 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. + * + */ +/* + * SATA support based on the chip canyonlands. + * + * 04-17-2009 + * The local version of this driver for the canyonlands board + * does not use interrupts but polls the chip instead. + */ + +#include <common.h> +#include <command.h> +#include <pci.h> +#include <asm/processor.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <malloc.h> +#include <ata.h> +#include <linux/ctype.h> + +#include "sata_dwc.h" + +#define DMA_NUM_CHANS 1 +#define DMA_NUM_CHAN_REGS 8 + +#define AHB_DMA_BRST_DFLT 16 + +struct dmareg { + u32 low; + u32 high; +}; + +struct dma_chan_regs { + struct dmareg sar; + struct dmareg dar; + struct dmareg llp; + struct dmareg ctl; + struct dmareg sstat; + struct dmareg dstat; + struct dmareg sstatar; + struct dmareg dstatar; + struct dmareg cfg; + struct dmareg sgr; + struct dmareg dsr; +}; + +struct dma_interrupt_regs { + struct dmareg tfr; + struct dmareg block; + struct dmareg srctran; + struct dmareg dsttran; + struct dmareg error; +}; + +struct ahb_dma_regs { + struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS]; + struct dma_interrupt_regs interrupt_raw; + struct dma_interrupt_regs interrupt_status; + struct dma_interrupt_regs interrupt_mask; + struct dma_interrupt_regs interrupt_clear; + struct dmareg statusInt; + struct dmareg rq_srcreg; + struct dmareg rq_dstreg; + struct dmareg rq_sgl_srcreg; + struct dmareg rq_sgl_dstreg; + struct dmareg rq_lst_srcreg; + struct dmareg rq_lst_dstreg; + struct dmareg dma_cfg; + struct dmareg dma_chan_en; + struct dmareg dma_id; + struct dmareg dma_test; + struct dmareg res1; + struct dmareg res2; + /* DMA Comp Params + * Param 6 = dma_param[0], Param 5 = dma_param[1], + * Param 4 = dma_param[2] ... + */ + struct dmareg dma_params[6]; +}; + +#define DMA_EN 0x00000001 +#define DMA_DI 0x00000000 +#define DMA_CHANNEL(ch) (0x00000001 << (ch)) +#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \ + ((0x000000001 << (ch)) << 8)) +#define DMA_DISABLE_CHAN(ch) (0x00000000 | \ + ((0x000000001 << (ch)) << 8)) + +#define SATA_DWC_MAX_PORTS 1 +#define SATA_DWC_SCR_OFFSET 0x24 +#define SATA_DWC_REG_OFFSET 0x64 + +struct sata_dwc_regs { + u32 fptagr; + u32 fpbor; + u32 fptcr; + u32 dmacr; + u32 dbtsr; + u32 intpr; + u32 intmr; + u32 errmr; + u32 llcr; + u32 phycr; + u32 physr; + u32 rxbistpd; + u32 rxbistpd1; + u32 rxbistpd2; + u32 txbistpd; + u32 txbistpd1; + u32 txbistpd2; + u32 bistcr; + u32 bistfctr; + u32 bistsr; + u32 bistdecr; + u32 res[15]; + u32 testr; + u32 versionr; + u32 idr; + u32 unimpl[192]; + u32 dmadr[256]; +}; + +#define SATA_DWC_TXFIFO_DEPTH 0x01FF +#define SATA_DWC_RXFIFO_DEPTH 0x01FF + +#define SATA_DWC_DBTSR_MWR(size) ((size / 4) & SATA_DWC_TXFIFO_DEPTH) +#define SATA_DWC_DBTSR_MRD(size) (((size / 4) & \ + SATA_DWC_RXFIFO_DEPTH) << 16) +#define SATA_DWC_INTPR_DMAT 0x00000001 +#define SATA_DWC_INTPR_NEWFP 0x00000002 +#define SATA_DWC_INTPR_PMABRT 0x00000004 +#define SATA_DWC_INTPR_ERR 0x00000008 +#define SATA_DWC_INTPR_NEWBIST 0x00000010 +#define SATA_DWC_INTPR_IPF 0x10000000 +#define SATA_DWC_INTMR_DMATM 0x00000001 +#define SATA_DWC_INTMR_NEWFPM 0x00000002 +#define SATA_DWC_INTMR_PMABRTM 0x00000004 +#define SATA_DWC_INTMR_ERRM 0x00000008 +#define SATA_DWC_INTMR_NEWBISTM 0x00000010 + +#define SATA_DWC_DMACR_TMOD_TXCHEN 0x00000004 +#define SATA_DWC_DMACR_TXRXCH_CLEAR SATA_DWC_DMACR_TMOD_TXCHEN + +#define SATA_DWC_QCMD_MAX 32 + +#define SATA_DWC_SERROR_ERR_BITS 0x0FFF0F03 + +#define HSDEVP_FROM_AP(ap) (struct sata_dwc_device_port*) \ + (ap)->private_data + +struct sata_dwc_device { + struct device *dev; + struct ata_probe_ent *pe; + struct ata_host *host; + u8 *reg_base; + struct sata_dwc_regs *sata_dwc_regs; + int irq_dma; +}; + +struct sata_dwc_device_port { + struct sata_dwc_device *hsdev; + int cmd_issued[SATA_DWC_QCMD_MAX]; + u32 dma_chan[SATA_DWC_QCMD_MAX]; + int dma_pending[SATA_DWC_QCMD_MAX]; +}; + +enum { + SATA_DWC_CMD_ISSUED_NOT = 0, + SATA_DWC_CMD_ISSUED_PEND = 1, + SATA_DWC_CMD_ISSUED_EXEC = 2, + SATA_DWC_CMD_ISSUED_NODATA = 3, + + SATA_DWC_DMA_PENDING_NONE = 0, + SATA_DWC_DMA_PENDING_TX = 1, + SATA_DWC_DMA_PENDING_RX = 2, +}; + +#define msleep(a) udelay(a * 1000) +#define ssleep(a) msleep(a * 1000) + +static int ata_probe_timeout = (ATA_TMOUT_INTERNAL / 100); + +enum sata_dev_state { + SATA_INIT = 0, + SATA_READY = 1, + SATA_NODEVICE = 2, + SATA_ERROR = 3, +}; +enum sata_dev_state dev_state = SATA_INIT; + +static struct ahb_dma_regs *sata_dma_regs = 0; +static struct ata_host *phost; +static struct ata_port ap; +static struct ata_port *pap = ≈ +static struct ata_device ata_device; +static struct sata_dwc_device_port dwc_devp; + +static void *scr_addr_sstatus; +static u32 temp_n_block = 0; + +static unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout); +static unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable,u8 feature); +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors); +static u8 ata_irq_on(struct ata_port *ap); +static struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag); +static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq); +static void ata_tf_to_host(struct ata_port *ap, + const struct ata_taskfile *tf); +static void ata_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf); +static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc); +static u8 ata_check_altstatus(struct ata_port *ap); +static u8 ata_check_status(struct ata_port *ap); +static void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep); +static void ata_qc_issue(struct ata_queued_cmd *qc); +static void ata_tf_load(struct ata_port *ap, + const struct ata_taskfile *tf); +static int ata_dev_read_sectors(unsigned char* pdata, + unsigned long datalen, u32 block, u32 n_block); +static int ata_dev_write_sectors(unsigned char* pdata, + unsigned long datalen , u32 block, u32 n_block); +static void ata_std_dev_select(struct ata_port *ap, unsigned int device); +static void ata_qc_complete(struct ata_queued_cmd *qc); +static void __ata_qc_complete(struct ata_queued_cmd *qc); +static void fill_result_tf(struct ata_queued_cmd *qc); +static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); +static void ata_mmio_data_xfer(struct ata_device *dev, + unsigned char *buf, + unsigned int buflen,int do_write); +static void ata_pio_task(struct ata_port *arg_ap); +static void __ata_port_freeze(struct ata_port *ap); +static int ata_port_freeze(struct ata_port *ap); +static void ata_qc_free(struct ata_queued_cmd *qc); +static void ata_pio_sectors(struct ata_queued_cmd *qc); +static void ata_pio_sector(struct ata_queued_cmd *qc); +static void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay); +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq); +static int sata_dwc_softreset(struct ata_port *ap); +static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id); +static int check_sata_dev_state(void); + +extern block_dev_desc_t sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE]; + +static const struct ata_port_info sata_dwc_port_info[] = { + { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING | + ATA_FLAG_SRST | ATA_FLAG_NCQ, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, + .udma_mask = 0x7f, + }, +}; + +int init_sata(int dev) +{ + struct sata_dwc_device hsdev; + struct ata_host host; + struct ata_port_info pi = sata_dwc_port_info[0]; + struct ata_link *link; + struct sata_dwc_device_port hsdevp = dwc_devp; + u8 *base = 0; + u8 *sata_dma_regs_addr = 0; + u8 status; + unsigned long base_addr = 0; + int chan = 0; + int rc; + int i; + + phost = &host; + + base = (u8*)SATA_BASE_ADDR; + + hsdev.sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); + + host.n_ports = SATA_DWC_MAX_PORTS; + + for (i = 0; i < SATA_DWC_MAX_PORTS; i++) { + ap.pflags |= ATA_PFLAG_INITIALIZING; + ap.flags = ATA_FLAG_DISABLED; + ap.print_id = -1; + ap.ctl = ATA_DEVCTL_OBS; + ap.host = &host; + ap.last_ctl = 0xFF; + + link = &ap.link; + link->ap = ≈ + link->pmp = 0; + link->active_tag = ATA_TAG_POISON; + link->hw_sata_spd_limit = 0; + + ap.port_no = i; + host.ports[i] = ≈ + } + + ap.pio_mask = pi.pio_mask; + ap.mwdma_mask = pi.mwdma_mask; + ap.udma_mask = pi.udma_mask; + ap.flags |= pi.flags; + ap.link.flags |= pi.link_flags; + + host.ports[0]->ioaddr.cmd_addr = base; + host.ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; + scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET; + + base_addr = (unsigned long)base; + + host.ports[0]->ioaddr.cmd_addr = (void *)base_addr + 0x00; + host.ports[0]->ioaddr.data_addr = (void *)base_addr + 0x00; + + host.ports[0]->ioaddr.error_addr = (void *)base_addr + 0x04; + host.ports[0]->ioaddr.feature_addr = (void *)base_addr + 0x04; + + host.ports[0]->ioaddr.nsect_addr = (void *)base_addr + 0x08; + + host.ports[0]->ioaddr.lbal_addr = (void *)base_addr + 0x0c; + host.ports[0]->ioaddr.lbam_addr = (void *)base_addr + 0x10; + host.ports[0]->ioaddr.lbah_addr = (void *)base_addr + 0x14; + + host.ports[0]->ioaddr.device_addr = (void *)base_addr + 0x18; + host.ports[0]->ioaddr.command_addr = (void *)base_addr + 0x1c; + host.ports[0]->ioaddr.status_addr = (void *)base_addr + 0x1c; + + host.ports[0]->ioaddr.altstatus_addr = (void *)base_addr + 0x20; + host.ports[0]->ioaddr.ctl_addr = (void *)base_addr + 0x20; + + sata_dma_regs_addr = (u8*)SATA_DMA_REG_ADDR; + sata_dma_regs = (void *__iomem)sata_dma_regs_addr; + + status = ata_check_altstatus(&ap); + + if (status == 0x7f) { + printf("Hard Disk not found.\n"); + dev_state = SATA_NODEVICE; + rc = FALSE; + return rc; + } + + printf("Waiting for device..."); + i = 0; + while (1) { + udelay(10000); + + status = ata_check_altstatus(&ap); + + if ((status & ATA_BUSY) == 0) { + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + dev_state = SATA_NODEVICE; + rc = FALSE; + return rc; + } + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + rc = sata_dwc_softreset(&ap); + + if (rc) { + printf("sata_dwc : error. soft reset failed\n"); + return rc; + } + + for (chan = 0; chan < DMA_NUM_CHANS; chan++) { + out_le32(&(sata_dma_regs->interrupt_mask.error.low), + DMA_DISABLE_CHAN(chan)); + + out_le32(&(sata_dma_regs->interrupt_mask.tfr.low), + DMA_DISABLE_CHAN(chan)); + } + + out_le32(&(sata_dma_regs->dma_cfg.low), DMA_DI); + + out_le32(&hsdev.sata_dwc_regs->intmr, + SATA_DWC_INTMR_ERRM | + SATA_DWC_INTMR_PMABRTM); + + /* Unmask the error bits that should trigger + * an error interrupt by setting the error mask register. + */ + out_le32(&hsdev.sata_dwc_regs->errmr, SATA_DWC_SERROR_ERR_BITS); + + hsdev.host = ap.host; + memset(&hsdevp, 0, sizeof(hsdevp)); + hsdevp.hsdev = &hsdev; + + for (i = 0; i < SATA_DWC_QCMD_MAX; i++) + hsdevp.cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; + + out_le32((void __iomem *)scr_addr_sstatus + 4, + in_le32((void __iomem *)scr_addr_sstatus + 4)); + + rc = 0; + return rc; +} + +static u8 ata_check_altstatus(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.altstatus_addr); + return val; +} + +static int sata_dwc_softreset(struct ata_port *ap) +{ + u8 nsect,lbal = 0; + u8 tmp = 0; + u32 serror = 0; + u8 status = 0; + struct ata_ioports *ioaddr = &ap->ioaddr; + + serror = in_le32((void *)ap->ioaddr.scr_addr + (SCR_ERROR * 4)); + + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + writeb(0xaa, ioaddr->nsect_addr); + writeb(0x55, ioaddr->lbal_addr); + writeb(0x55, ioaddr->nsect_addr); + writeb(0xaa, ioaddr->lbal_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + if ((nsect == 0x55) && (lbal == 0xaa)) { + printf("Device found\n"); + } else { + printf("No device found\n"); + dev_state = SATA_NODEVICE; + return FALSE; + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp, ioaddr->device_addr); + writeb(ap->ctl, ioaddr->ctl_addr); + + udelay(200); + + writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr); + + udelay(200); + writeb(ap->ctl, ioaddr->ctl_addr); + + msleep(150); + status = ata_check_status(ap); + + msleep(50); + ata_check_status(ap); + + while (1) { + u8 status = ata_check_status(ap); + + if (!(status & ATA_BUSY)) + break; + + printf("Hard Disk status is BUSY.\n"); + msleep(50); + } + + tmp = ATA_DEVICE_OBS; + writeb(tmp, ioaddr->device_addr); + + nsect = readb(ioaddr->nsect_addr); + lbal = readb(ioaddr->lbal_addr); + + return 0; +} + +static u8 ata_check_status(struct ata_port *ap) +{ + u8 val = 0; + val = readb(ap->ioaddr.status_addr); + return val; +} + +static int ata_id_has_hipm(const u16 *id) +{ + u16 val = id[76]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 9); +} + +static int ata_id_has_dipm(const u16 *id) +{ + u16 val = id[78]; + + if (val == 0 || val == 0xffff) + return -1; + + return val & (1 << 3); +} + +int scan_sata(int dev) +{ + int i; + int rc; + u8 status; + const u16 *id; + struct ata_device *ata_dev = &ata_device; + unsigned long pio_mask, mwdma_mask, udma_mask; + unsigned long xfer_mask; + char revbuf[7]; + u16 iobuf[ATA_SECTOR_WORDS]; + + memset(iobuf, 0, sizeof(iobuf)); + + if (dev_state == SATA_NODEVICE) + return 1; + + printf("Waiting for device..."); + i = 0; + while (1) { + udelay(10000); + + status = ata_check_altstatus(&ap); + + if ((status & ATA_BUSY) == 0) { + printf("\n"); + break; + } + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + + dev_state = SATA_NODEVICE; + return 1; + } + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + udelay(1000); + + rc = ata_dev_read_id(ata_dev, &ata_dev->class, + ATA_READID_POSTRESET,ata_dev->id); + if (rc) { + printf("sata_dwc : error. failed sata scan\n"); + return 1; + } + + /* SATA drives indicate we have a bridge. We don't know which + * end of the link the bridge is which is a problem + */ + if (ata_id_is_sata(ata_dev->id)) + ap.cbl = ATA_CBL_SATA; + + id = ata_dev->id; + + ata_dev->flags &= ~ATA_DFLAG_CFG_MASK; + ata_dev->max_sectors = 0; + ata_dev->cdb_len = 0; + ata_dev->n_sectors = 0; + ata_dev->cylinders = 0; + ata_dev->heads = 0; + ata_dev->sectors = 0; + + if (id[ATA_ID_FIELD_VALID] & (1 << 1)) { + pio_mask = id[ATA_ID_PIO_MODES] & 0x03; + pio_mask <<= 3; + pio_mask |= 0x7; + } else { + /* If word 64 isn't valid then Word 51 high byte holds + * the PIO timing number for the maximum. Turn it into + * a mask. + */ + u8 mode = (id[ATA_ID_OLD_PIO_MODES] >> 8) & 0xFF; + if (mode < 5) { + pio_mask = (2 << mode) - 1; + } else { + pio_mask = 1; + } + } + + mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07; + + if (ata_id_is_cfa(id)) { + int pio = id[163] & 0x7; + int dma = (id[163] >> 3) & 7; + + if (pio) + pio_mask |= (1 << 5); + if (pio > 1) + pio_mask |= (1 << 6); + if (dma) + mwdma_mask |= (1 << 3); + if (dma > 1) + mwdma_mask |= (1 << 4); + } + + udma_mask = 0; + if (id[ATA_ID_FIELD_VALID] & (1 << 2)) + udma_mask = id[ATA_ID_UDMA_MODES] & 0xff; + + xfer_mask = ((pio_mask << ATA_SHIFT_PIO) & ATA_MASK_PIO) | + ((mwdma_mask << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA) | + ((udma_mask << ATA_SHIFT_UDMA) & ATA_MASK_UDMA); + + if (ata_dev->class == ATA_DEV_ATA) { + if (ata_id_is_cfa(id)) { + if (id[162] & 1) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + sprintf(revbuf, "%s", "CFA"); + } else { + if (ata_id_has_tpm(id)) + printf("supports DRM functions and may " + "not be fully accessable.\n"); + } + + ata_dev->n_sectors = ata_id_n_sectors((u16*)id); + + if (ata_dev->id[59] & 0x100) + ata_dev->multi_count = ata_dev->id[59] & 0xff; + + if (ata_id_has_lba(id)) { + const char *lba_desc; + char ncq_desc[20]; + + lba_desc = "LBA"; + ata_dev->flags |= ATA_DFLAG_LBA; + if (ata_id_has_lba48(id)) { + ata_dev->flags |= ATA_DFLAG_LBA48; + lba_desc = "LBA48"; + + if (ata_dev->n_sectors >= (1UL << 28) && + ata_id_has_flush_ext(id)) + ata_dev->flags |= ATA_DFLAG_FLUSH_EXT; + } + if (!ata_id_has_ncq(ata_dev->id)) + ncq_desc[0] = '\0'; + + if (ata_dev->horkage & ATA_HORKAGE_NONCQ) + sprintf(ncq_desc, "%s", "NCQ (not used)"); + + if (ap.flags & ATA_FLAG_NCQ) + ata_dev->flags |= ATA_DFLAG_NCQ; + } + ata_dev->cdb_len = 16; + } + ata_dev->max_sectors = ATA_MAX_SECTORS; + if (ata_dev->flags & ATA_DFLAG_LBA48) + ata_dev->max_sectors = ATA_MAX_SECTORS_LBA48; + + if (!(ata_dev->horkage & ATA_HORKAGE_IPM)) { + if (ata_id_has_hipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_HIPM; + if (ata_id_has_dipm(ata_dev->id)) + ata_dev->flags |= ATA_DFLAG_DIPM; + } + + if ((ap.cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ata_dev->id))) { + ata_dev->udma_mask &= ATA_UDMA5; + ata_dev->max_sectors = ATA_MAX_SECTORS; + } + + if (ata_dev->horkage & ATA_HORKAGE_DIAGNOSTIC) { + printf("Drive reports diagnostics failure." + "This may indicate a drive\n"); + printf("fault or invalid emulation." + "Contact drive vendor for information.\n"); + } + + rc = check_sata_dev_state(); + + ata_id_c_string(ata_dev->id, + (unsigned char *)sata_dev_desc[dev].revision, + ATA_ID_FW_REV, sizeof(sata_dev_desc[dev].revision)); + ata_id_c_string(ata_dev->id, + (unsigned char *)sata_dev_desc[dev].vendor, + ATA_ID_PROD, sizeof(sata_dev_desc[dev].vendor)); + ata_id_c_string(ata_dev->id, + (unsigned char *)sata_dev_desc[dev].product, + ATA_ID_SERNO, sizeof(sata_dev_desc[dev].product)); + + sata_dev_desc[dev].lba = (u32) ata_dev->n_sectors; + +#ifdef CONFIG_LBA48 + if (ata_dev->id[83] & (1 << 10)) { + sata_dev_desc[dev].lba48 = 1; + } else { + sata_dev_desc[dev].lba48 = 0; + } +#endif + + return 0; +} + +static u8 ata_busy_wait(struct ata_port *ap, + unsigned int bits,unsigned int max) +{ + u8 status; + + do { + udelay(10); + status = ata_check_status(ap); + max--; + } while (status != 0xff && (status & bits) && (max > 0)); + + return status; +} + +static int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, + unsigned int flags, u16 *id) +{ + struct ata_port *ap = pap; + unsigned int class = *p_class; + struct ata_taskfile tf; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1, tried_spinup = 0; + u8 status; + int rc; + + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = FALSE; + return rc; + } + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_ID_ATA; + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + + /* Device presence detection is unreliable on some + * controllers. Always poll IDENTIFY if available. + */ + tf.flags |= ATA_TFLAG_POLLING; + + temp_n_block = 1; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, + sizeof(id[0]) * ATA_ID_WORDS, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + unsigned int id_cnt; + + for (id_cnt = 0; id_cnt < ATA_ID_WORDS; id_cnt++) + id[id_cnt] = le16_to_cpu(id[id_cnt]); + + + rc = -EINVAL; + reason = "device reports invalid type"; + + if (class == ATA_DEV_ATA) { + if (!ata_id_is_ata(id) && !ata_id_is_cfa(id)) + goto err_out; + } else { + if (ata_id_is_ata(id)) + goto err_out; + } + if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) { + tried_spinup = 1; + /* + * Drive powered-up in standby mode, and requires a specific + * SET_FEATURES spin-up subcommand before it will accept + * anything other than the original IDENTIFY command. + */ + err_mask = ata_dev_set_feature(dev, SETFEATURES_SPINUP, 0); + if (err_mask && id[2] != 0x738c) { + rc = -EIO; + reason = "SPINUP failed"; + goto err_out; + } + /* + * If the drive initially returned incomplete IDENTIFY info, + * we now must reissue the IDENTIFY command. + */ + if (id[2] == 0x37c8) + goto retry; + } + + if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) { + /* + * The exact sequence expected by certain pre-ATA4 drives is: + * SRST RESET + * IDENTIFY (optional in early ATA) + * INITIALIZE DEVICE PARAMETERS (later IDE and ATA) + * anything else.. + * Some drives were very specific about that exact sequence. + * + * Note that ATA4 says lba is mandatory so the second check + * shoud never trigger. + */ + if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) { + err_mask = ata_dev_init_params(dev, id[3], id[6]); + if (err_mask) { + rc = -EIO; + reason = "INIT_DEV_PARAMS failed"; + goto err_out; + } + + /* current CHS translation info (id[53-58]) might be + * changed. reread the identify device info. + */ + flags &= ~ATA_READID_POSTRESET; + goto retry; + } + } + + *p_class = class; + return 0; + +err_out: + return rc; +} + +static u8 ata_wait_idle(struct ata_port *ap) +{ + u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); + return status; +} + +static void ata_dev_select(struct ata_port *ap, unsigned int device, + unsigned int wait, unsigned int can_sleep) +{ + if (wait) + ata_wait_idle(ap); + + ata_std_dev_select(ap, device); + + if (wait) + ata_wait_idle(ap); +} + +static void ata_std_dev_select(struct ata_port *ap, unsigned int device) +{ + u8 tmp; + + if (device == 0) { + tmp = ATA_DEVICE_OBS; + } else { + tmp = ATA_DEVICE_OBS | ATA_DEV1; + } + + writeb(tmp, ap->ioaddr.device_addr); + + readb(ap->ioaddr.altstatus_addr); + + udelay(1); +} + +static int waiting_for_reg_state(volatile u8 *offset, + int timeout_msec, + u32 sign) +{ + int i; + u32 status; + + for (i = 0; i < timeout_msec; i++) { + status = readl(offset); + if ((status & sign) != 0) + break; + msleep(1); + } + + return (i < timeout_msec) ? 0 : -1; +} + +static void ata_qc_reinit(struct ata_queued_cmd *qc) +{ + qc->dma_dir = DMA_NONE; + qc->flags = 0; + qc->nbytes = qc->extrabytes = qc->curbytes = 0; + qc->n_elem = 0; + qc->err_mask = 0; + qc->sect_size = ATA_SECT_SIZE; + qc->nbytes = ATA_SECT_SIZE * temp_n_block; + + memset(&qc->tf, 0, sizeof(qc->tf)); + qc->tf.ctl = 0; + qc->tf.device = ATA_DEVICE_OBS; + + qc->result_tf.command = ATA_DRDY; + qc->result_tf.feature = 0; +} + +struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, + unsigned int tag) +{ + if (tag < ATA_MAX_QUEUE) + return &ap->qcmd[tag]; + return NULL; +} + +static void __ata_port_freeze(struct ata_port *ap) +{ + printf("set port freeze.\n"); + ap->pflags |= ATA_PFLAG_FROZEN; +} + +static int ata_port_freeze(struct ata_port *ap) +{ + __ata_port_freeze(ap); + return 0; +} + +unsigned ata_exec_internal(struct ata_device *dev, + struct ata_taskfile *tf, const u8 *cdb, + int dma_dir, unsigned int buflen, + unsigned long timeout) +{ + struct ata_link *link = dev->link; + struct ata_port *ap = pap; + struct ata_queued_cmd *qc; + unsigned int tag, preempted_tag; + u32 preempted_sactive, preempted_qc_active; + int preempted_nr_active_links; + unsigned int err_mask; + int rc = 0; + u8 status; + + status = ata_busy_wait(ap, ATA_BUSY, 300000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + rc = FALSE; + return rc; + } + + if (ap->pflags & ATA_PFLAG_FROZEN) + return AC_ERR_SYSTEM; + + tag = ATA_TAG_INTERNAL; + + if (test_and_set_bit(tag, &ap->qc_allocated)) { + rc = FALSE; + return rc; + } + + qc = __ata_qc_from_tag(ap, tag); + qc->tag = tag; + qc->ap = ap; + qc->dev = dev; + + ata_qc_reinit(qc); + + preempted_tag = link->active_tag; + preempted_sactive = link->sactive; + preempted_qc_active = ap->qc_active; + preempted_nr_active_links = ap->nr_active_links; + link->active_tag = ATA_TAG_POISON; + link->sactive = 0; + ap->qc_active = 0; + ap->nr_active_links = 0; + + qc->tf = *tf; + if (cdb) + memcpy(qc->cdb, cdb, ATAPI_CDB_LEN); + qc->flags |= ATA_QCFLAG_RESULT_TF; + qc->dma_dir = dma_dir; + qc->private_data = 0; + + ata_qc_issue(qc); + + if (!timeout) + timeout = ata_probe_timeout * 1000 / HZ; + + status = ata_busy_wait(ap, ATA_BUSY, 30000); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + printf("altstatus = 0x%x.\n", status); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + if (waiting_for_reg_state(ap->ioaddr.altstatus_addr, 1000, 0x8)) { + u8 status = 0; + u8 errorStatus = 0; + + status = readb(ap->ioaddr.altstatus_addr); + if ((status & 0x01) != 0) { + errorStatus = readb(ap->ioaddr.feature_addr); + if (errorStatus == 0x04 && + qc->tf.command == ATA_CMD_PIO_READ_EXT){ + printf("Hard Disk doesn't support LBA48\n"); + dev_state = SATA_ERROR; + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + } + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + status = ata_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + printf("BSY = 0 check. timeout.\n"); + qc->err_mask |= AC_ERR_OTHER; + return qc->err_mask; + } + + ata_pio_task(ap); + + if (!rc) { + if (qc->flags & ATA_QCFLAG_ACTIVE) { + qc->err_mask |= AC_ERR_TIMEOUT; + ata_port_freeze(ap); + } + } + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (qc->result_tf.command & (ATA_ERR | ATA_DF)) + qc->err_mask |= AC_ERR_DEV; + + if (!qc->err_mask) + qc->err_mask |= AC_ERR_OTHER; + + if (qc->err_mask & ~AC_ERR_OTHER) + qc->err_mask &= ~AC_ERR_OTHER; + } + + *tf = qc->result_tf; + err_mask = qc->err_mask; + ata_qc_free(qc); + link->active_tag = preempted_tag; + link->sactive = preempted_sactive; + ap->qc_active = preempted_qc_active; + ap->nr_active_links = preempted_nr_active_links; + + if (ap->flags & ATA_FLAG_DISABLED) { + err_mask |= AC_ERR_SYSTEM; + ap->flags &= ~ATA_FLAG_DISABLED; + } + + return err_mask; +} + +static void ata_qc_issue(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + u8 prot = qc->tf.protocol; + + if (ata_is_ncq(prot)) { + if (!link->sactive) + ap->nr_active_links++; + link->sactive |= 1 << qc->tag; + } else { + ap->nr_active_links++; + link->active_tag = qc->tag; + } + + qc->flags |= ATA_QCFLAG_ACTIVE; + ap->qc_active |= 1 << qc->tag; + + if (qc->dev->flags & ATA_DFLAG_SLEEPING) { + msleep(1); + return; + } + + qc->err_mask |= ata_qc_issue_prot(qc); + if (qc->err_mask) + goto err; + + return; +err: + ata_qc_complete(qc); +} + +static unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + if (ap->flags & ATA_FLAG_PIO_POLLING) { + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + case ATA_PROT_NODATA: + case ATAPI_PROT_PIO: + case ATAPI_PROT_NODATA: + qc->tf.flags |= ATA_TFLAG_POLLING; + break; + default: + break; + } + } + + ata_dev_select(ap, qc->dev->devno, 1, 0); + + switch (qc->tf.protocol) { + case ATA_PROT_PIO: + if (qc->tf.flags & ATA_TFLAG_POLLING) + qc->tf.ctl |= ATA_NIEN; + + ata_tf_to_host(ap, &qc->tf); + + ap->hsm_task_state = HSM_ST; + + if (qc->tf.flags & ATA_TFLAG_POLLING) + ata_pio_queue_task(ap, qc, 0); + + break; + + default: + return AC_ERR_SYSTEM; + } + + return 0; +} + +static void ata_tf_to_host(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + ata_tf_load(ap, tf); + ata_exec_command(ap, tf); +} + +static void ata_tf_load(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + if (ioaddr->ctl_addr) + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + writeb(tf->hob_feature, ioaddr->feature_addr); + writeb(tf->hob_nsect, ioaddr->nsect_addr); + writeb(tf->hob_lbal, ioaddr->lbal_addr); + writeb(tf->hob_lbam, ioaddr->lbam_addr); + writeb(tf->hob_lbah, ioaddr->lbah_addr); + } + + if (is_addr) { + writeb(tf->feature, ioaddr->feature_addr); + writeb(tf->nsect, ioaddr->nsect_addr); + writeb(tf->lbal, ioaddr->lbal_addr); + writeb(tf->lbam, ioaddr->lbam_addr); + writeb(tf->lbah, ioaddr->lbah_addr); + } + + if (tf->flags & ATA_TFLAG_DEVICE) + writeb(tf->device, ioaddr->device_addr); + + ata_wait_idle(ap); +} + +static void ata_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + writeb(tf->command, ap->ioaddr.command_addr); + + readb(ap->ioaddr.altstatus_addr); + + udelay(1); +} + +static void ata_pio_queue_task(struct ata_port *ap, + void *data,unsigned long delay) +{ + ap->port_task_data = data; +} + +static unsigned int ac_err_mask(u8 status) +{ + if (status & (ATA_BUSY | ATA_DRQ)) + return AC_ERR_HSM; + if (status & (ATA_ERR | ATA_DF)) + return AC_ERR_DEV; + return 0; +} + +static unsigned int __ac_err_mask(u8 status) +{ + unsigned int mask = ac_err_mask(status); + if (mask == 0) + return AC_ERR_OTHER; + return mask; +} + +static void ata_pio_task(struct ata_port *arg_ap) +{ + struct ata_port *ap = arg_ap; + struct ata_queued_cmd *qc = ap->port_task_data; + u8 status; + int poll_next; + +fsm_start: + /* + * This is purely heuristic. This is a fast path. + * Sometimes when we enter, BSY will be cleared in + * a chk-status or two. If not, the drive is probably seeking + * or something. Snooze for a couple msecs, then + * chk-status again. If still busy, queue delayed work. + */ + status = ata_busy_wait(ap, ATA_BUSY, 5); + if (status & ATA_BUSY) { + msleep(2); + status = ata_busy_wait(ap, ATA_BUSY, 10); + if (status & ATA_BUSY) { + ata_pio_queue_task(ap, qc, ATA_SHORT_PAUSE); + return; + } + } + + poll_next = ata_hsm_move(ap, qc, status, 1); + + /* another command or interrupt handler + * may be running at this point. + */ + if (poll_next) + goto fsm_start; +} + +static int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, + u8 status, int in_wq) +{ + int poll_next; + +fsm_start: + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + poll_next = (qc->tf.flags & ATA_TFLAG_POLLING); + + if ((status & ATA_DRQ) == 0) { + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + } else { + qc->err_mask |= AC_ERR_HSM; + } + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + /* Device should not ask for data transfer (DRQ=1) + * when it finds something wrong. + * We ignore DRQ here and stop the HSM by + * changing hsm_task_state to HSM_ST_ERR and + * let the EH abort the command or reset the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) { + printf("DRQ=1 with device error, " + "dev_stat 0x%X\n", status); + qc->err_mask |= AC_ERR_HSM; + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + } + + if (qc->tf.protocol == ATA_PROT_PIO) { + /* PIO data out protocol. + * send first data block. + */ + /* ata_pio_sectors() might change the state + * to HSM_ST_LAST. so, the state is changed here + * before ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST; + ata_pio_sectors(qc); + } else { + printf("protocol is not ATA_PROT_PIO \n"); + } + break; + + case HSM_ST: + if ((status & ATA_DRQ) == 0) { + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + } else { + /* HSM violation. Let EH handle this. + * Phantom devices also trigger this + * condition. Mark hint. + */ + qc->err_mask |= AC_ERR_HSM | AC_ERR_NODEV_HINT; + } + + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + /* For PIO reads, some devices may ask for + * data transfer (DRQ=1) alone with ERR=1. + * We respect DRQ here and transfer one + * block of junk data before changing the + * hsm_task_state to HSM_ST_ERR. + * + * For PIO writes, ERR=1 DRQ=1 doesn't make + * sense since the data block has been + * transferred to the device. + */ + if (status & (ATA_ERR | ATA_DF)) { + qc->err_mask |= AC_ERR_DEV; + + if (!(qc->tf.flags & ATA_TFLAG_WRITE)) { + ata_pio_sectors(qc); + status = ata_wait_idle(ap); + } + + if (status & (ATA_BUSY | ATA_DRQ)) + qc->err_mask |= AC_ERR_HSM; + + /* ata_pio_sectors() might change the + * state to HSM_ST_LAST. so, the state + * is changed after ata_pio_sectors(). + */ + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ata_pio_sectors(qc); + if (ap->hsm_task_state == HSM_ST_LAST && + (!(qc->tf.flags & ATA_TFLAG_WRITE))) { + status = ata_wait_idle(ap); + goto fsm_start; + } + + poll_next = 1; + break; + + case HSM_ST_LAST: + if (!ata_ok(status)) { + qc->err_mask |= __ac_err_mask(status); + ap->hsm_task_state = HSM_ST_ERR; + goto fsm_start; + } + + ap->hsm_task_state = HSM_ST_IDLE; + + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + + case HSM_ST_ERR: + /* make sure qc->err_mask is available to + * know what's wrong and recover + */ + ap->hsm_task_state = HSM_ST_IDLE; + + ata_hsm_qc_complete(qc, in_wq); + + poll_next = 0; + break; + default: + poll_next = 0; + } + + return poll_next; +} + +static void ata_pio_sectors(struct ata_queued_cmd *qc) +{ + struct ata_port *ap; + ap = pap; + qc->pdata = ap->pdata; + + ata_pio_sector(qc); + + readb(qc->ap->ioaddr.altstatus_addr); + udelay(1); +} + +static void ata_pio_sector(struct ata_queued_cmd *qc) +{ + int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); + struct ata_port *ap = qc->ap; + unsigned int offset; + unsigned char *buf; + char temp_data_buf[512]; + + if (qc->curbytes == qc->nbytes - qc->sect_size) + ap->hsm_task_state = HSM_ST_LAST; + + offset = qc->curbytes; + + switch (qc->tf.command) { + case ATA_CMD_ID_ATA: + buf = (unsigned char *)&ata_device.id[0]; + break; + case ATA_CMD_PIO_READ_EXT: + case ATA_CMD_PIO_READ: + case ATA_CMD_PIO_WRITE_EXT: + case ATA_CMD_PIO_WRITE: + buf = qc->pdata + offset; + break; + default: + buf = (unsigned char *)&temp_data_buf[0]; + } + + ata_mmio_data_xfer(qc->dev, buf, qc->sect_size, do_write); + + qc->curbytes += qc->sect_size; + +} + +static void ata_mmio_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int do_write) +{ + struct ata_port *ap = pap; + void __iomem *data_addr = ap->ioaddr.data_addr; + unsigned int words = buflen >> 1; + u16 *buf16 = (u16 *)buf; + unsigned int i = 0; + + udelay(100); + if (do_write) { + for (i = 0; i < words; i++) + writew(le16_to_cpu(buf16[i]), data_addr); + } else { + for (i = 0; i < words; i++) + buf16[i] = cpu_to_le16(readw(data_addr)); + } + + if (buflen & 0x01) { + __le16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (do_write) { + memcpy(align_buf, trailing_buf, 1); + writew(le16_to_cpu(align_buf[0]), data_addr); + } else { + align_buf[0] = cpu_to_le16(readw(data_addr)); + memcpy(trailing_buf, align_buf, 1); + } + } +} + +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) +{ + struct ata_port *ap = qc->ap; + + if (in_wq) { + /* EH might have kicked in while host lock is + * released. + */ + qc = &ap->qcmd[qc->tag]; + if (qc) { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_irq_on(ap); + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } + } else { + if (!(qc->err_mask & AC_ERR_HSM)) { + ata_qc_complete(qc); + } else { + ata_port_freeze(ap); + } + } +} + +static u8 ata_irq_on(struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + if (ioaddr->ctl_addr) + writeb(ap->ctl, ioaddr->ctl_addr); + + tmp = ata_wait_idle(ap); + + return tmp; +} + +static unsigned int ata_tag_internal(unsigned int tag) +{ + return tag == ATA_MAX_QUEUE - 1; +} + +static void ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_device *dev = qc->dev; + if (qc->err_mask) + qc->flags |= ATA_QCFLAG_FAILED; + + if (qc->flags & ATA_QCFLAG_FAILED) { + if (!ata_tag_internal(qc->tag)) { + fill_result_tf(qc); + return; + } + } + if (qc->flags & ATA_QCFLAG_RESULT_TF) + fill_result_tf(qc); + + /* Some commands need post-processing after successful + * completion. + */ + switch (qc->tf.command) { + case ATA_CMD_SET_FEATURES: + if (qc->tf.feature != SETFEATURES_WC_ON && + qc->tf.feature != SETFEATURES_WC_OFF) + break; + case ATA_CMD_INIT_DEV_PARAMS: + case ATA_CMD_SET_MULTI: + break; + + case ATA_CMD_SLEEP: + dev->flags |= ATA_DFLAG_SLEEPING; + break; + } + + __ata_qc_complete(qc); +} + +static void fill_result_tf(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + + qc->result_tf.flags = qc->tf.flags; + ata_tf_read(ap, &qc->result_tf); +} + +static void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = ata_check_status(ap); + tf->feature = readb(ioaddr->error_addr); + tf->nsect = readb(ioaddr->nsect_addr); + tf->lbal = readb(ioaddr->lbal_addr); + tf->lbam = readb(ioaddr->lbam_addr); + tf->lbah = readb(ioaddr->lbah_addr); + tf->device = readb(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + if (ioaddr->ctl_addr) { + writeb(tf->ctl | ATA_HOB, ioaddr->ctl_addr); + + tf->hob_feature = readb(ioaddr->error_addr); + tf->hob_nsect = readb(ioaddr->nsect_addr); + tf->hob_lbal = readb(ioaddr->lbal_addr); + tf->hob_lbam = readb(ioaddr->lbam_addr); + tf->hob_lbah = readb(ioaddr->lbah_addr); + + writeb(tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } else { + printf("sata_dwc warnning register read.\n"); + } + } +} + +static void __ata_qc_complete(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct ata_link *link = qc->dev->link; + + link->active_tag = ATA_TAG_POISON; + ap->nr_active_links--; + + if (qc->flags & ATA_QCFLAG_CLEAR_EXCL && ap->excl_link == link) + ap->excl_link = NULL; + + qc->flags &= ~ATA_QCFLAG_ACTIVE; + ap->qc_active &= ~(1 << qc->tag); +} + +static void ata_qc_free(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int tag; + qc->flags = 0; + tag = qc->tag; + if (tag < ATA_MAX_QUEUE) { + qc->tag = ATA_TAG_POISON; + clear_bit(tag, &ap->qc_allocated); + } +} + +static int check_sata_dev_state(void) +{ + unsigned long datalen; + unsigned char *pdata; + int ret = 0; + int i = 0; + char temp_data_buf[512]; + + while (1) { + udelay(10000); + + pdata = (unsigned char*)&temp_data_buf[0]; + datalen = 512; + + ret = ata_dev_read_sectors(pdata, datalen, 0, 1); + + if (ret == TRUE) + break; + + i++; + if (i > (ATA_RESET_TIME * 100)) { + printf("** TimeOUT **\n"); + dev_state = SATA_NODEVICE; + return FALSE; + } + + if ((i >= 100) && ((i % 100) == 0)) + printf("."); + } + + dev_state = SATA_READY; + + return TRUE; +} + +static unsigned int ata_dev_set_feature(struct ata_device *dev, + u8 enable, u8 feature) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_SET_FEATURES; + tf.feature = enable; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = feature; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + return err_mask; +} + +static unsigned int ata_dev_init_params(struct ata_device *dev, + u16 heads, u16 sectors) +{ + struct ata_taskfile tf; + struct ata_port *ap; + ap = pap; + unsigned int err_mask; + + if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) + return AC_ERR_INVALID; + + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + tf.device = ATA_DEVICE_OBS; + tf.command = ATA_CMD_INIT_DEV_PARAMS; + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.protocol = ATA_PROT_NODATA; + tf.nsect = sectors; + tf.device |= (heads - 1) & 0x0f; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, 0, 0); + + if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED)) + err_mask = 0; + + return err_mask; +} + +#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) +#define SATA_MAX_READ_BLK 0xFF +#else +#define SATA_MAX_READ_BLK 0xFFFF +#endif + +ulong sata_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + ulong start,blks, buf_addr; + unsigned short smallblks; + unsigned long datalen; + unsigned char *pdata; + device &= 0xff; + + u32 block = 0; + u32 n_block = 0; + + if (dev_state != SATA_READY) + return 0; + + buf_addr = (unsigned long)buffer; + start = blknr; + blks = blkcnt; + do { + pdata = (unsigned char *)buf_addr; + if (blks > SATA_MAX_READ_BLK) { + datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; + smallblks = SATA_MAX_READ_BLK; + + block = (u32)start; + n_block = (u32)smallblks; + + start += SATA_MAX_READ_BLK; + blks -= SATA_MAX_READ_BLK; + } else { + datalen = sata_dev_desc[device].blksz * SATA_MAX_READ_BLK; + datalen = sata_dev_desc[device].blksz * blks; + smallblks = (unsigned short)blks; + + block = (u32)start; + n_block = (u32)smallblks; + + start += blks; + blks = 0; + } + + if (ata_dev_read_sectors(pdata, datalen, block, n_block) != TRUE) { + printf("sata_dwc : Hard disk read error.\n"); + blkcnt -= blks; + break; + } + buf_addr += datalen; + } while (blks != 0); + + return (blkcnt); +} + +static int ata_dev_read_sectors(unsigned char *pdata, unsigned long datalen, + u32 block, u32 n_block) +{ + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + int rc; + + if (dev_state == SATA_ERROR) + return FALSE; + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + ap->pdata = pdata; + + tf.device = ATA_DEVICE_OBS; + + temp_n_block = n_block; + +#ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_READ_EXT; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; +#else + tf.command = ATA_CMD_PIO_READ; + tf.flags |= ATA_TFLAG_LBA ; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + +#endif + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, 0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + rc = -EINVAL; + reason = "device reports invalid type"; + + return TRUE; + +err_out: + printf("failed to READ SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return FALSE; +} + +#if defined(CONFIG_SATA_DWC) && !defined(CONFIG_LBA48) +#define SATA_MAX_WRITE_BLK 0xFF +#else +#define SATA_MAX_WRITE_BLK 0xFFFF +#endif + +ulong sata_write(int device, ulong blknr, lbaint_t blkcnt, void *buffer) +{ + ulong start,blks, buf_addr; + unsigned short smallblks; + unsigned long datalen; + unsigned char *pdata; + device &= 0xff; + + + u32 block = 0; + u32 n_block = 0; + + if (dev_state != SATA_READY) + return 0; + + buf_addr = (unsigned long)buffer; + start = blknr; + blks = blkcnt; + do { + pdata = (unsigned char *)buf_addr; + if (blks > SATA_MAX_WRITE_BLK) { + datalen = sata_dev_desc[device].blksz * SATA_MAX_WRITE_BLK; + smallblks = SATA_MAX_WRITE_BLK; + + block = (u32)start; + n_block = (u32)smallblks; + + start += SATA_MAX_WRITE_BLK; + blks -= SATA_MAX_WRITE_BLK; + } else { + datalen = sata_dev_desc[device].blksz * blks; + smallblks = (unsigned short)blks; + + block = (u32)start; + n_block = (u32)smallblks; + + start += blks; + blks = 0; + } + + if (ata_dev_write_sectors(pdata, datalen, block, n_block) != TRUE) { + printf("sata_dwc : Hard disk read error.\n"); + blkcnt -= blks; + break; + } + buf_addr += datalen; + } while (blks != 0); + + return (blkcnt); +} + +static int ata_dev_write_sectors(unsigned char* pdata, unsigned long datalen, + u32 block, u32 n_block) +{ + struct ata_port *ap = pap; + struct ata_device *dev = &ata_device; + struct ata_taskfile tf; + unsigned int class = ATA_DEV_ATA; + unsigned int err_mask = 0; + const char *reason; + int may_fallback = 1; + int rc; + + if (dev_state == SATA_ERROR) + return FALSE; + + ata_dev_select(ap, dev->devno, 1, 1); + +retry: + memset(&tf, 0, sizeof(tf)); + tf.ctl = ap->ctl; + ap->print_id = 1; + ap->flags &= ~ATA_FLAG_DISABLED; + + ap->pdata = pdata; + + tf.device = ATA_DEVICE_OBS; + + temp_n_block = n_block; + + +#ifdef CONFIG_LBA48 + tf.command = ATA_CMD_PIO_WRITE_EXT; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_LBA48 | ATA_TFLAG_WRITE; + + tf.hob_feature = 31; + tf.feature = 31; + tf.hob_nsect = (n_block >> 8) & 0xff; + tf.nsect = n_block & 0xff; + + tf.hob_lbah = 0x0; + tf.hob_lbam = 0x0; + tf.hob_lbal = (block >> 24) & 0xff; + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; +#else + tf.command = ATA_CMD_PIO_WRITE; + tf.flags |= ATA_TFLAG_LBA | ATA_TFLAG_WRITE; + + tf.feature = 31; + tf.nsect = n_block & 0xff; + + tf.lbah = (block >> 16) & 0xff; + tf.lbam = (block >> 8) & 0xff; + tf.lbal = block & 0xff; + + tf.device = (block >> 24) & 0xf; + + tf.device |= 1 << 6; + if (tf.flags & ATA_TFLAG_FUA) + tf.device |= 1 << 7; + +#endif + + tf.protocol = ATA_PROT_PIO; + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf.flags |= ATA_TFLAG_POLLING; + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, 0, 0); + + if (err_mask) { + if (err_mask & AC_ERR_NODEV_HINT) { + printf("READ_SECTORS NODEV after polling detection\n"); + return -ENOENT; + } + + if ((err_mask == AC_ERR_DEV) && (tf.feature & ATA_ABORTED)) { + /* Device or controller might have reported + * the wrong device class. Give a shot at the + * other IDENTIFY if the current one is + * aborted by the device. + */ + if (may_fallback) { + may_fallback = 0; + + if (class == ATA_DEV_ATA) { + class = ATA_DEV_ATAPI; + } else { + class = ATA_DEV_ATA; + } + goto retry; + } + /* Control reaches here iff the device aborted + * both flavors of IDENTIFYs which happens + * sometimes with phantom devices. + */ + printf("both IDENTIFYs aborted, assuming NODEV\n"); + return -ENOENT; + } + + rc = -EIO; + reason = "I/O error"; + goto err_out; + } + + /* Falling back doesn't make sense if ID data was read + * successfully at least once. + */ + may_fallback = 0; + + rc = -EINVAL; + reason = "device reports invalid type"; + + return TRUE; + +err_out: + printf("failed to WRITE SECTORS (%s, err_mask=0x%x)\n", reason, err_mask); + return FALSE; +} diff --git a/drivers/block/sata_dwc.h b/drivers/block/sata_dwc.h new file mode 100644 index 0000000..204d644 --- /dev/null +++ b/drivers/block/sata_dwc.h @@ -0,0 +1,477 @@ +/* + * sata_dwc.h + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld <mmiesfeld@amcc.com> + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr@denx.de> + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * 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. + * + */ +/* + * SATA support based on the chip canyonlands. + * + * 04-17-2009 + * The local version of this driver for the canyonlands board + * does not use interrupts but polls the chip instead. + */ + + +#ifndef _SATA_DWC_H_ +#define _SATA_DWC_H_ + +#define __U_BOOT__ + +#define HZ 100 +#define READ 0 +#define WRITE 1 + +enum { + ATA_READID_POSTRESET = (1 << 0), + + ATA_DNXFER_PIO = 0, + ATA_DNXFER_DMA = 1, + ATA_DNXFER_40C = 2, + ATA_DNXFER_FORCE_PIO = 3, + ATA_DNXFER_FORCE_PIO0 = 4, + + ATA_DNXFER_QUIET = (1 << 31), +}; + +enum hsm_task_states { + HSM_ST_IDLE, + HSM_ST_FIRST, + HSM_ST, + HSM_ST_LAST, + HSM_ST_ERR, +}; + +#define ATA_SHORT_PAUSE ((HZ >> 6) + 1) + +struct ata_queued_cmd { + struct ata_port *ap; + struct ata_device *dev; + + struct ata_taskfile tf; + u8 cdb[ATAPI_CDB_LEN]; + unsigned long flags; + unsigned int tag; + unsigned int n_elem; + + int dma_dir; + unsigned int sect_size; + + unsigned int nbytes; + unsigned int extrabytes; + unsigned int curbytes; + + unsigned int err_mask; + struct ata_taskfile result_tf; + + void *private_data; +#ifndef __U_BOOT__ + void *lldd_task; +#endif + unsigned char *pdata; +}; + +typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc); + +#define ATA_TAG_POISON 0xfafbfcfdU + +enum { + LIBATA_MAX_PRD = ATA_MAX_PRD / 2, + LIBATA_DUMB_MAX_PRD = ATA_MAX_PRD / 4, + ATA_MAX_PORTS = 8, + ATA_DEF_QUEUE = 1, + ATA_MAX_QUEUE = 32, + ATA_TAG_INTERNAL = ATA_MAX_QUEUE - 1, + ATA_MAX_BUS = 2, + ATA_DEF_BUSY_WAIT = 10000, + + ATAPI_MAX_DRAIN = 16 << 10, + + ATA_SHT_EMULATED = 1, + ATA_SHT_CMD_PER_LUN = 1, + ATA_SHT_THIS_ID = -1, + ATA_SHT_USE_CLUSTERING = 1, + + ATA_DFLAG_LBA = (1 << 0), + ATA_DFLAG_LBA48 = (1 << 1), + ATA_DFLAG_CDB_INTR = (1 << 2), + ATA_DFLAG_NCQ = (1 << 3), + ATA_DFLAG_FLUSH_EXT = (1 << 4), + ATA_DFLAG_ACPI_PENDING = (1 << 5), + ATA_DFLAG_ACPI_FAILED = (1 << 6), + ATA_DFLAG_AN = (1 << 7), + ATA_DFLAG_HIPM = (1 << 8), + ATA_DFLAG_DIPM = (1 << 9), + ATA_DFLAG_DMADIR = (1 << 10), + ATA_DFLAG_CFG_MASK = (1 << 12) - 1, + + ATA_DFLAG_PIO = (1 << 12), + ATA_DFLAG_NCQ_OFF = (1 << 13), + ATA_DFLAG_SPUNDOWN = (1 << 14), + ATA_DFLAG_SLEEPING = (1 << 15), + ATA_DFLAG_DUBIOUS_XFER = (1 << 16), + ATA_DFLAG_INIT_MASK = (1 << 24) - 1, + + ATA_DFLAG_DETACH = (1 << 24), + ATA_DFLAG_DETACHED = (1 << 25), + + ATA_LFLAG_HRST_TO_RESUME = (1 << 0), + ATA_LFLAG_SKIP_D2H_BSY = (1 << 1), + ATA_LFLAG_NO_SRST = (1 << 2), + ATA_LFLAG_ASSUME_ATA = (1 << 3), + ATA_LFLAG_ASSUME_SEMB = (1 << 4), + ATA_LFLAG_ASSUME_CLASS = ATA_LFLAG_ASSUME_ATA | ATA_LFLAG_ASSUME_SEMB, + ATA_LFLAG_NO_RETRY = (1 << 5), + ATA_LFLAG_DISABLED = (1 << 6), + + ATA_FLAG_SLAVE_POSS = (1 << 0), + ATA_FLAG_SATA = (1 << 1), + ATA_FLAG_NO_LEGACY = (1 << 2), + ATA_FLAG_MMIO = (1 << 3), + ATA_FLAG_SRST = (1 << 4), + ATA_FLAG_SATA_RESET = (1 << 5), + ATA_FLAG_NO_ATAPI = (1 << 6), + ATA_FLAG_PIO_DMA = (1 << 7), + ATA_FLAG_PIO_LBA48 = (1 << 8), + ATA_FLAG_PIO_POLLING = (1 << 9), + ATA_FLAG_NCQ = (1 << 10), + ATA_FLAG_DEBUGMSG = (1 << 13), + ATA_FLAG_IGN_SIMPLEX = (1 << 15), + ATA_FLAG_NO_IORDY = (1 << 16), + ATA_FLAG_ACPI_SATA = (1 << 17), + ATA_FLAG_AN = (1 << 18), + ATA_FLAG_PMP = (1 << 19), + ATA_FLAG_IPM = (1 << 20), + + ATA_FLAG_DISABLED = (1 << 23), + + ATA_PFLAG_EH_PENDING = (1 << 0), + ATA_PFLAG_EH_IN_PROGRESS = (1 << 1), + ATA_PFLAG_FROZEN = (1 << 2), + ATA_PFLAG_RECOVERED = (1 << 3), + ATA_PFLAG_LOADING = (1 << 4), + ATA_PFLAG_UNLOADING = (1 << 5), + ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), + ATA_PFLAG_INITIALIZING = (1 << 7), + ATA_PFLAG_RESETTING = (1 << 8), + ATA_PFLAG_SUSPENDED = (1 << 17), + ATA_PFLAG_PM_PENDING = (1 << 18), + + ATA_QCFLAG_ACTIVE = (1 << 0), + ATA_QCFLAG_DMAMAP = (1 << 1), + ATA_QCFLAG_IO = (1 << 3), + ATA_QCFLAG_RESULT_TF = (1 << 4), + ATA_QCFLAG_CLEAR_EXCL = (1 << 5), + ATA_QCFLAG_QUIET = (1 << 6), + + ATA_QCFLAG_FAILED = (1 << 16), + ATA_QCFLAG_SENSE_VALID = (1 << 17), + ATA_QCFLAG_EH_SCHEDULED = (1 << 18), + + ATA_HOST_SIMPLEX = (1 << 0), + ATA_HOST_STARTED = (1 << 1), + + ATA_TMOUT_BOOT = 30 * 100, + ATA_TMOUT_BOOT_QUICK = 7 * 100, + ATA_TMOUT_INTERNAL = 30 * 100, + ATA_TMOUT_INTERNAL_QUICK = 5 * 100, + + /* FIXME: GoVault needs 2s but we can't afford that without + * parallel probing. 800ms is enough for iVDR disk + * HHD424020F7SV00. Increase to 2secs when parallel probing + * is in place. + */ + ATA_TMOUT_FF_WAIT = 4 * 100 / 5, + + BUS_UNKNOWN = 0, + BUS_DMA = 1, + BUS_IDLE = 2, + BUS_NOINTR = 3, + BUS_NODATA = 4, + BUS_TIMER = 5, + BUS_PIO = 6, + BUS_EDD = 7, + BUS_IDENTIFY = 8, + BUS_PACKET = 9, + + PORT_UNKNOWN = 0, + PORT_ENABLED = 1, + PORT_DISABLED = 2, + + /* encoding various smaller bitmaps into a single + * unsigned long bitmap + */ + ATA_NR_PIO_MODES = 7, + ATA_NR_MWDMA_MODES = 5, + ATA_NR_UDMA_MODES = 8, + + ATA_SHIFT_PIO = 0, + ATA_SHIFT_MWDMA = ATA_SHIFT_PIO + ATA_NR_PIO_MODES, + ATA_SHIFT_UDMA = ATA_SHIFT_MWDMA + ATA_NR_MWDMA_MODES, + + ATA_DMA_PAD_SZ = 4, + + ATA_ERING_SIZE = 32, + + ATA_DEFER_LINK = 1, + ATA_DEFER_PORT = 2, + + ATA_EH_DESC_LEN = 80, + + ATA_EH_REVALIDATE = (1 << 0), + ATA_EH_SOFTRESET = (1 << 1), + ATA_EH_HARDRESET = (1 << 2), + ATA_EH_ENABLE_LINK = (1 << 3), + ATA_EH_LPM = (1 << 4), + + ATA_EH_RESET_MASK = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, + ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, + + ATA_EHI_HOTPLUGGED = (1 << 0), + ATA_EHI_RESUME_LINK = (1 << 1), + ATA_EHI_NO_AUTOPSY = (1 << 2), + ATA_EHI_QUIET = (1 << 3), + + ATA_EHI_DID_SOFTRESET = (1 << 16), + ATA_EHI_DID_HARDRESET = (1 << 17), + ATA_EHI_PRINTINFO = (1 << 18), + ATA_EHI_SETMODE = (1 << 19), + ATA_EHI_POST_SETMODE = (1 << 20), + + ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET, + ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK, + + ATA_EH_MAX_TRIES = 5, + + ATA_PROBE_MAX_TRIES = 3, + ATA_EH_DEV_TRIES = 3, + ATA_EH_PMP_TRIES = 5, + ATA_EH_PMP_LINK_TRIES = 3, + + SATA_PMP_SCR_TIMEOUT = 250, + + /* Horkage types. May be set by libata or controller on drives + (some horkage may be drive/controller pair dependant */ + + ATA_HORKAGE_DIAGNOSTIC = (1 << 0), + ATA_HORKAGE_NODMA = (1 << 1), + ATA_HORKAGE_NONCQ = (1 << 2), + ATA_HORKAGE_MAX_SEC_128 = (1 << 3), + ATA_HORKAGE_BROKEN_HPA = (1 << 4), + ATA_HORKAGE_SKIP_PM = (1 << 5), + ATA_HORKAGE_HPA_SIZE = (1 << 6), + ATA_HORKAGE_IPM = (1 << 7), + ATA_HORKAGE_IVB = (1 << 8), + ATA_HORKAGE_STUCK_ERR = (1 << 9), + + ATA_DMA_MASK_ATA = (1 << 0), + ATA_DMA_MASK_ATAPI = (1 << 1), + ATA_DMA_MASK_CFA = (1 << 2), + + ATAPI_READ = 0, + ATAPI_WRITE = 1, + ATAPI_READ_CD = 2, + ATAPI_PASS_THRU = 3, + ATAPI_MISC = 4, +}; + +enum ata_completion_errors { + AC_ERR_DEV = (1 << 0), + AC_ERR_HSM = (1 << 1), + AC_ERR_TIMEOUT = (1 << 2), + AC_ERR_MEDIA = (1 << 3), + AC_ERR_ATA_BUS = (1 << 4), + AC_ERR_HOST_BUS = (1 << 5), + AC_ERR_SYSTEM = (1 << 6), + AC_ERR_INVALID = (1 << 7), + AC_ERR_OTHER = (1 << 8), + AC_ERR_NODEV_HINT = (1 << 9), + AC_ERR_NCQ = (1 << 10), +}; + +enum ata_xfer_mask { + ATA_MASK_PIO = ((1LU << ATA_NR_PIO_MODES) - 1) << ATA_SHIFT_PIO, + ATA_MASK_MWDMA = ((1LU << ATA_NR_MWDMA_MODES) - 1) << ATA_SHIFT_MWDMA, + ATA_MASK_UDMA = ((1LU << ATA_NR_UDMA_MODES) - 1) << ATA_SHIFT_UDMA, +}; + +struct ata_port_info { +#ifndef __U_BOOT__ + struct scsi_host_template *sht; +#endif + unsigned long flags; + unsigned long link_flags; + unsigned long pio_mask; + unsigned long mwdma_mask; + unsigned long udma_mask; +#ifndef __U_BOOT__ + const struct ata_port_operations *port_ops; + void *private_data; +#endif +}; + +struct ata_ioports { + void __iomem *cmd_addr; + void __iomem *data_addr; + void __iomem *error_addr; + void __iomem *feature_addr; + void __iomem *nsect_addr; + void __iomem *lbal_addr; + void __iomem *lbam_addr; + void __iomem *lbah_addr; + void __iomem *device_addr; + void __iomem *status_addr; + void __iomem *command_addr; + void __iomem *altstatus_addr; + void __iomem *ctl_addr; +#ifndef __U_BOOT__ + void __iomem *bmdma_addr; +#endif + void __iomem *scr_addr; +}; + +struct ata_host { +#ifndef __U_BOOT__ + void __iomem * const *iomap; + void *private_data; + const struct ata_port_operations *ops; + unsigned long flags; + struct ata_port *simplex_claimed; +#endif + unsigned int n_ports; + struct ata_port *ports[0]; +}; + +#ifndef __U_BOOT__ +struct ata_port_stats { + unsigned long unhandled_irq; + unsigned long idle_irq; + unsigned long rw_reqbuf; +}; +#endif + +struct ata_device { + struct ata_link *link; + unsigned int devno; + unsigned long flags; + unsigned int horkage; +#ifndef __U_BOOT__ + struct scsi_device *sdev; +#ifdef CONFIG_ATA_ACPI + acpi_handle acpi_handle; + union acpi_object *gtf_cache; +#endif +#endif + u64 n_sectors; + unsigned int class; + + union { + u16 id[ATA_ID_WORDS]; + u32 gscr[SATA_PMP_GSCR_DWORDS]; + }; +#ifndef __U_BOOT__ + u8 pio_mode; + u8 dma_mode; + u8 xfer_mode; + unsigned int xfer_shift; +#endif + unsigned int multi_count; + unsigned int max_sectors; + unsigned int cdb_len; +#ifndef __U_BOOT__ + unsigned long pio_mask; + unsigned long mwdma_mask; +#endif + unsigned long udma_mask; + u16 cylinders; + u16 heads; + u16 sectors; +#ifndef __U_BOOT__ + int spdn_cnt; +#endif +}; + +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +struct ata_link { + struct ata_port *ap; + int pmp; + unsigned int active_tag; + u32 sactive; + unsigned int flags; + unsigned int hw_sata_spd_limit; +#ifndef __U_BOOT__ + unsigned int sata_spd_limit; + unsigned int sata_spd; + struct ata_device device[2]; +#endif +}; + +struct ata_port { + unsigned long flags; + unsigned int pflags; + unsigned int print_id; + unsigned int port_no; + + struct ata_ioports ioaddr; + + u8 ctl; + u8 last_ctl; + unsigned int pio_mask; + unsigned int mwdma_mask; + unsigned int udma_mask; + unsigned int cbl; + + struct ata_queued_cmd qcmd[ATA_MAX_QUEUE]; + unsigned long qc_allocated; + unsigned int qc_active; + int nr_active_links; + + struct ata_link link; +#ifndef __U_BOOT__ + int nr_pmp_links; + struct ata_link *pmp_link; +#endif + struct ata_link *excl_link; + int nr_pmp_links; +#ifndef __U_BOOT__ + struct ata_port_stats stats; + struct device *dev; + u32 msg_enable; +#endif + struct ata_host *host; + void *port_task_data; + + unsigned int hsm_task_state; + void *private_data; + unsigned char *pdata; +}; + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index f10144f..acba56c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -25,6 +25,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libgpio.a +COBJS-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o COBJS-$(CONFIG_MX31_GPIO) += mx31_gpio.o COBJS-$(CONFIG_PCA953X) += pca953x.o diff --git a/drivers/gpio/kw_gpio.c b/drivers/gpio/kw_gpio.c new file mode 100644 index 0000000..1c28834 --- /dev/null +++ b/drivers/gpio/kw_gpio.c @@ -0,0 +1,151 @@ +/* + * arch/arm/plat-orion/gpio.c + * + * Marvell Orion SoC GPIO handling. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +/* + * Based on (mostly copied from) plat-orion based Linux 2.6 kernel driver. + * Removed orion_gpiochip struct and kernel level irq handling. + * + * Dieter Kiermaier dk-arm-linux@gmx.de + */ + +#include <common.h> +#include <asm/bitops.h> +#include <asm/arch/kirkwood.h> +#include <asm/arch/gpio.h> + +static unsigned long gpio_valid_input[BITS_TO_LONGS(GPIO_MAX)]; +static unsigned long gpio_valid_output[BITS_TO_LONGS(GPIO_MAX)]; + +void __set_direction(unsigned pin, int input) +{ + u32 u; + + u = readl(GPIO_IO_CONF(pin)); + if (input) + u |= 1 << (pin & 31); + else + u &= ~(1 << (pin & 31)); + writel(u, GPIO_IO_CONF(pin)); + + u = readl(GPIO_IO_CONF(pin)); +} + +void __set_level(unsigned pin, int high) +{ + u32 u; + + u = readl(GPIO_OUT(pin)); + if (high) + u |= 1 << (pin & 31); + else + u &= ~(1 << (pin & 31)); + writel(u, GPIO_OUT(pin)); +} + +void __set_blinking(unsigned pin, int blink) +{ + u32 u; + + u = readl(GPIO_BLINK_EN(pin)); + if (blink) + u |= 1 << (pin & 31); + else + u &= ~(1 << (pin & 31)); + writel(u, GPIO_BLINK_EN(pin)); +} + +int kw_gpio_is_valid(unsigned pin, int mode) +{ + if (pin < GPIO_MAX) { + if ((mode & GPIO_INPUT_OK) && !test_bit(pin, gpio_valid_input)) + goto err_out; + + if ((mode & GPIO_OUTPUT_OK) && !test_bit(pin, gpio_valid_output)) + goto err_out; + return 0; + } + +err_out: + printf("%s: invalid GPIO %d\n", __func__, pin); + return 1; +} + +void kw_gpio_set_valid(unsigned pin, int mode) +{ + if (mode == 1) + mode = GPIO_INPUT_OK | GPIO_OUTPUT_OK; + if (mode & GPIO_INPUT_OK) + __set_bit(pin, gpio_valid_input); + else + __clear_bit(pin, gpio_valid_input); + if (mode & GPIO_OUTPUT_OK) + __set_bit(pin, gpio_valid_output); + else + __clear_bit(pin, gpio_valid_output); +} +/* + * GENERIC_GPIO primitives. + */ +int kw_gpio_direction_input(unsigned pin) +{ + if (!kw_gpio_is_valid(pin, GPIO_INPUT_OK)) + return 1; + + /* Configure GPIO direction. */ + __set_direction(pin, 1); + + return 0; +} + +int kw_gpio_direction_output(unsigned pin, int value) +{ + if (kw_gpio_is_valid(pin, GPIO_OUTPUT_OK) != 0) + { + printf("%s: invalid GPIO %d\n", __func__, pin); + return 1; + } + + __set_blinking(pin, 0); + + /* Configure GPIO output value. */ + __set_level(pin, value); + + /* Configure GPIO direction. */ + __set_direction(pin, 0); + + return 0; +} + +int kw_gpio_get_value(unsigned pin) +{ + int val; + + if (readl(GPIO_IO_CONF(pin)) & (1 << (pin & 31))) + val = readl(GPIO_DATA_IN(pin)) ^ readl(GPIO_IN_POL(pin)); + else + val = readl(GPIO_OUT(pin)); + + return (val >> (pin & 31)) & 1; +} + +void kw_gpio_set_value(unsigned pin, int value) +{ + /* Configure GPIO output value. */ + __set_level(pin, value); +} + +void kw_gpio_set_blink(unsigned pin, int blink) +{ + /* Set output value to zero. */ + __set_level(pin, 0); + + /* Set blinking. */ + __set_blinking(pin, blink); +} diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index ef32f13..4a12976 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -28,6 +28,7 @@ LIB := $(obj)libi2c.a COBJS-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o COBJS-$(CONFIG_DRIVER_DAVINCI_I2C) += davinci_i2c.o COBJS-$(CONFIG_FSL_I2C) += fsl_i2c.o +COBJS-$(CONFIG_I2C_KIRKWOOD) += kirkwood_i2c.o COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o COBJS-$(CONFIG_DRIVER_OMAP1510_I2C) += omap1510_i2c.o COBJS-$(CONFIG_DRIVER_OMAP24XX_I2C) += omap24xx_i2c.o diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c index 6ab7d3d..ce0f301 100644 --- a/drivers/i2c/fsl_i2c.c +++ b/drivers/i2c/fsl_i2c.c @@ -178,6 +178,12 @@ i2c_init(int speed, int slaveadd) struct fsl_i2c *dev; unsigned int temp; +#ifdef CONFIG_SYS_I2C_INIT_BOARD + /* call board specific i2c bus reset routine before accessing the */ + /* environment, which might be in a chip on that bus. For details */ + /* about this problem see doc/I2C_Edge_Conditions. */ + i2c_init_board(); +#endif dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET); writeb(0, &dev->cr); /* stop I2C controller */ diff --git a/drivers/i2c/kirkwood_i2c.c b/drivers/i2c/kirkwood_i2c.c new file mode 100644 index 0000000..dd30499 --- /dev/null +++ b/drivers/i2c/kirkwood_i2c.c @@ -0,0 +1,484 @@ +/* + * Driver for the i2c controller on the Marvell line of host bridges + * (e.g, gt642[46]0, mv643[46]0, mv644[46]0, Orion SoC family), + * and Kirkwood family. + * + * Based on: + * Author: Mark A. Greer <mgreer@mvista.com> + * + * 2005 (c) MontaVista, Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + * + * ported from Linux to u-boot + * (C) Copyright 2009 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * + */ +#include <common.h> +#include <i2c.h> +#include <asm/arch/kirkwood.h> +#include <asm/errno.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +static unsigned int i2c_bus_num __attribute__ ((section (".data"))) = 0; +#if defined(CONFIG_I2C_MUX) +static unsigned int i2c_bus_num_mux __attribute__ ((section ("data"))) = 0; +#endif + +/* Register defines */ +#define KW_I2C_REG_SLAVE_ADDR 0x00 +#define KW_I2C_REG_DATA 0x04 +#define KW_I2C_REG_CONTROL 0x08 +#define KW_I2C_REG_STATUS 0x0c +#define KW_I2C_REG_BAUD 0x0c +#define KW_I2C_REG_EXT_SLAVE_ADDR 0x10 +#define KW_I2C_REG_SOFT_RESET 0x1c + +#define KW_I2C_REG_CONTROL_ACK 0x00000004 +#define KW_I2C_REG_CONTROL_IFLG 0x00000008 +#define KW_I2C_REG_CONTROL_STOP 0x00000010 +#define KW_I2C_REG_CONTROL_START 0x00000020 +#define KW_I2C_REG_CONTROL_TWSIEN 0x00000040 +#define KW_I2C_REG_CONTROL_INTEN 0x00000080 + +/* Ctlr status values */ +#define KW_I2C_STATUS_BUS_ERR 0x00 +#define KW_I2C_STATUS_MAST_START 0x08 +#define KW_I2C_STATUS_MAST_REPEAT_START 0x10 +#define KW_I2C_STATUS_MAST_WR_ADDR_ACK 0x18 +#define KW_I2C_STATUS_MAST_WR_ADDR_NO_ACK 0x20 +#define KW_I2C_STATUS_MAST_WR_ACK 0x28 +#define KW_I2C_STATUS_MAST_WR_NO_ACK 0x30 +#define KW_I2C_STATUS_MAST_LOST_ARB 0x38 +#define KW_I2C_STATUS_MAST_RD_ADDR_ACK 0x40 +#define KW_I2C_STATUS_MAST_RD_ADDR_NO_ACK 0x48 +#define KW_I2C_STATUS_MAST_RD_DATA_ACK 0x50 +#define KW_I2C_STATUS_MAST_RD_DATA_NO_ACK 0x58 +#define KW_I2C_STATUS_MAST_WR_ADDR_2_ACK 0xd0 +#define KW_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK 0xd8 +#define KW_I2C_STATUS_MAST_RD_ADDR_2_ACK 0xe0 +#define KW_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK 0xe8 +#define KW_I2C_STATUS_NO_STATUS 0xf8 + +/* Driver states */ +enum { + KW_I2C_STATE_INVALID, + KW_I2C_STATE_IDLE, + KW_I2C_STATE_WAITING_FOR_START_COND, + KW_I2C_STATE_WAITING_FOR_ADDR_1_ACK, + KW_I2C_STATE_WAITING_FOR_ADDR_2_ACK, + KW_I2C_STATE_WAITING_FOR_SLAVE_ACK, + KW_I2C_STATE_WAITING_FOR_SLAVE_DATA, +}; + +/* Driver actions */ +enum { + KW_I2C_ACTION_INVALID, + KW_I2C_ACTION_CONTINUE, + KW_I2C_ACTION_SEND_START, + KW_I2C_ACTION_SEND_ADDR_1, + KW_I2C_ACTION_SEND_ADDR_2, + KW_I2C_ACTION_SEND_DATA, + KW_I2C_ACTION_RCV_DATA, + KW_I2C_ACTION_RCV_DATA_STOP, + KW_I2C_ACTION_SEND_STOP, +}; + +/* defines to get compatible with Linux driver */ +#define IRQ_NONE 0x0 +#define IRQ_HANDLED 0x01 + +#define I2C_M_TEN 0x01 +#define I2C_M_RD 0x02 +#define I2C_M_REV_DIR_ADDR 0x04; + +struct i2c_msg { + u32 addr; + u32 flags; + u8 *buf; + u32 len; +}; + +struct kirkwood_i2c_data { + int irq; + u32 state; + u32 action; + u32 aborting; + u32 cntl_bits; + void *reg_base; + u32 reg_base_p; + u32 reg_size; + u32 addr1; + u32 addr2; + u32 bytes_left; + u32 byte_posn; + u32 block; + int rc; + u32 freq_m; + u32 freq_n; + struct i2c_msg *msg; +}; + +static struct kirkwood_i2c_data __drv_data __attribute__ ((section (".data"))); +static struct kirkwood_i2c_data *drv_data = &__drv_data; +static struct i2c_msg __i2c_msg __attribute__ ((section (".data"))); +static struct i2c_msg *kirkwood_i2c_msg = &__i2c_msg; + +/* + ***************************************************************************** + * + * Finite State Machine & Interrupt Routines + * + ***************************************************************************** + */ + +static inline int abs(int n) +{ + if(n >= 0) + return n; + else + return n * -1; +} + +static void kirkwood_calculate_speed(int speed) +{ + int calcspeed; + int diff; + int best_diff = CONFIG_SYS_TCLK; + int best_speed = 0; + int m, n; + int tmp[8] = {2, 4, 8, 16, 32, 64, 128, 256}; + + for (n = 0; n < 8; n++) { + for (m = 0; m < 16; m++) { + calcspeed = CONFIG_SYS_TCLK / (10 * (m + 1) * tmp[n]); + diff = abs((speed - calcspeed)); + if ( diff < best_diff) { + best_diff = diff; + best_speed = calcspeed; + drv_data->freq_m = m; + drv_data->freq_n = n; + } + } + } +} + +/* Reset hardware and initialize FSM */ +static void +kirkwood_i2c_hw_init(int speed, int slaveadd) +{ + drv_data->state = KW_I2C_STATE_IDLE; + + kirkwood_calculate_speed(speed); + writel(0, CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_SOFT_RESET); + writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)), + CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_BAUD); + writel(slaveadd, CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_SLAVE_ADDR); + writel(0, CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_EXT_SLAVE_ADDR); + writel(KW_I2C_REG_CONTROL_TWSIEN | KW_I2C_REG_CONTROL_STOP, + CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_CONTROL); +} + +static void +kirkwood_i2c_fsm(u32 status) +{ + /* + * If state is idle, then this is likely the remnants of an old + * operation that driver has given up on or the user has killed. + * If so, issue the stop condition and go to idle. + */ + if (drv_data->state == KW_I2C_STATE_IDLE) { + drv_data->action = KW_I2C_ACTION_SEND_STOP; + return; + } + + /* The status from the ctlr [mostly] tells us what to do next */ + switch (status) { + /* Start condition interrupt */ + case KW_I2C_STATUS_MAST_START: /* 0x08 */ + case KW_I2C_STATUS_MAST_REPEAT_START: /* 0x10 */ + drv_data->action = KW_I2C_ACTION_SEND_ADDR_1; + drv_data->state = KW_I2C_STATE_WAITING_FOR_ADDR_1_ACK; + break; + + /* Performing a write */ + case KW_I2C_STATUS_MAST_WR_ADDR_ACK: /* 0x18 */ + if (drv_data->msg->flags & I2C_M_TEN) { + drv_data->action = KW_I2C_ACTION_SEND_ADDR_2; + drv_data->state = + KW_I2C_STATE_WAITING_FOR_ADDR_2_ACK; + break; + } + /* FALLTHRU */ + case KW_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */ + case KW_I2C_STATUS_MAST_WR_ACK: /* 0x28 */ + if ((drv_data->bytes_left == 0) + || (drv_data->aborting + && (drv_data->byte_posn != 0))) { + drv_data->action = KW_I2C_ACTION_SEND_STOP; + drv_data->state = KW_I2C_STATE_IDLE; + } else { + drv_data->action = KW_I2C_ACTION_SEND_DATA; + drv_data->state = + KW_I2C_STATE_WAITING_FOR_SLAVE_ACK; + drv_data->bytes_left--; + } + break; + + /* Performing a read */ + case KW_I2C_STATUS_MAST_RD_ADDR_ACK: /* 40 */ + if (drv_data->msg->flags & I2C_M_TEN) { + drv_data->action = KW_I2C_ACTION_SEND_ADDR_2; + drv_data->state = + KW_I2C_STATE_WAITING_FOR_ADDR_2_ACK; + break; + } + /* FALLTHRU */ + case KW_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */ + if (drv_data->bytes_left == 0) { + drv_data->action = KW_I2C_ACTION_SEND_STOP; + drv_data->state = KW_I2C_STATE_IDLE; + break; + } + /* FALLTHRU */ + case KW_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */ + if (status != KW_I2C_STATUS_MAST_RD_DATA_ACK) + drv_data->action = KW_I2C_ACTION_CONTINUE; + else { + drv_data->action = KW_I2C_ACTION_RCV_DATA; + drv_data->bytes_left--; + } + drv_data->state = KW_I2C_STATE_WAITING_FOR_SLAVE_DATA; + + if ((drv_data->bytes_left == 1) || drv_data->aborting) + drv_data->cntl_bits &= ~KW_I2C_REG_CONTROL_ACK; + break; + + case KW_I2C_STATUS_MAST_RD_DATA_NO_ACK: /* 0x58 */ + drv_data->action = KW_I2C_ACTION_RCV_DATA_STOP; + drv_data->state = KW_I2C_STATE_IDLE; + break; + + case KW_I2C_STATUS_MAST_WR_ADDR_NO_ACK: /* 0x20 */ + case KW_I2C_STATUS_MAST_WR_NO_ACK: /* 30 */ + case KW_I2C_STATUS_MAST_RD_ADDR_NO_ACK: /* 48 */ + /* Doesn't seem to be a device at other end */ + drv_data->action = KW_I2C_ACTION_SEND_STOP; + drv_data->state = KW_I2C_STATE_IDLE; + drv_data->rc = -ENODEV; + break; + + default: + printf("kirkwood_i2c_fsm: Ctlr Error -- state: 0x%x, " + "status: 0x%x, addr: 0x%x, flags: 0x%x\n", + drv_data->state, status, drv_data->msg->addr, + drv_data->msg->flags); + drv_data->action = KW_I2C_ACTION_SEND_STOP; + kirkwood_i2c_hw_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + drv_data->rc = -EIO; + } +} + +static void +kirkwood_i2c_do_action(void) +{ + switch(drv_data->action) { + case KW_I2C_ACTION_CONTINUE: + writel(drv_data->cntl_bits, + CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_CONTROL); + break; + + case KW_I2C_ACTION_SEND_START: + writel(drv_data->cntl_bits | KW_I2C_REG_CONTROL_START, + CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_CONTROL); + break; + + case KW_I2C_ACTION_SEND_ADDR_1: + writel(drv_data->addr1, + CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_DATA); + writel(drv_data->cntl_bits, + CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_CONTROL); + break; + + case KW_I2C_ACTION_SEND_ADDR_2: + writel(drv_data->addr2, + CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_DATA); + writel(drv_data->cntl_bits, + CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_CONTROL); + break; + + case KW_I2C_ACTION_SEND_DATA: + writel(drv_data->msg->buf[drv_data->byte_posn++], + CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_DATA); + writel(drv_data->cntl_bits, + CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_CONTROL); + break; + + case KW_I2C_ACTION_RCV_DATA: + drv_data->msg->buf[drv_data->byte_posn++] = + readl(CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_DATA); + writel(drv_data->cntl_bits, + CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_CONTROL); + break; + + case KW_I2C_ACTION_RCV_DATA_STOP: + drv_data->msg->buf[drv_data->byte_posn++] = + readl(CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_DATA); + drv_data->cntl_bits &= ~KW_I2C_REG_CONTROL_INTEN; + writel(drv_data->cntl_bits | KW_I2C_REG_CONTROL_STOP, + CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_CONTROL); + drv_data->block = 0; + break; + + case KW_I2C_ACTION_INVALID: + default: + printf("kirkwood_i2c_do_action: Invalid action: %d\n", + drv_data->action); + drv_data->rc = -EIO; + /* FALLTHRU */ + case KW_I2C_ACTION_SEND_STOP: + drv_data->cntl_bits &= ~KW_I2C_REG_CONTROL_INTEN; + writel(drv_data->cntl_bits | KW_I2C_REG_CONTROL_STOP, + CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_CONTROL); + drv_data->block = 0; + break; + } +} + +static int +kirkwood_i2c_intr(void) +{ + u32 status; + u32 ctrl; + int rc = IRQ_NONE; + + ctrl = readl(CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_CONTROL); + while ((ctrl & KW_I2C_REG_CONTROL_IFLG) && + (drv_data->rc == 0)) { + status = readl(CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_STATUS); + kirkwood_i2c_fsm(status); + kirkwood_i2c_do_action(); + rc = IRQ_HANDLED; + ctrl = readl(CONFIG_I2C_KW_REG_BASE + KW_I2C_REG_CONTROL); + udelay(1000); + } + return rc; +} + +static void +kirkwood_i2c_doio(struct i2c_msg *msg) +{ + int ret; + + while ((drv_data->rc == 0) && (drv_data->state != KW_I2C_STATE_IDLE)) { + /* poll Status register */ + ret = kirkwood_i2c_intr(); + if (ret == IRQ_NONE) + udelay(10); + } +} + +static void +kirkwood_i2c_prepare_for_io(struct i2c_msg *msg) +{ + u32 dir = 0; + + drv_data->msg = msg; + drv_data->byte_posn = 0; + drv_data->bytes_left = msg->len; + drv_data->aborting = 0; + drv_data->rc = 0; + /* in u-boot we use no IRQs */ + drv_data->cntl_bits = KW_I2C_REG_CONTROL_ACK | KW_I2C_REG_CONTROL_TWSIEN; + + if (msg->flags & I2C_M_RD) + dir = 1; + if (msg->flags & I2C_M_TEN) { + drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir; + drv_data->addr2 = (u32)msg->addr & 0xff; + } else { + drv_data->addr1 = ((u32)msg->addr & 0x7f) << 1 | dir; + drv_data->addr2 = 0; + } + /* OK, no start it (from kirkwood_i2c_execute_msg())*/ + drv_data->action = KW_I2C_ACTION_SEND_START; + drv_data->state = KW_I2C_STATE_WAITING_FOR_START_COND; + drv_data->block = 1; + kirkwood_i2c_do_action(); +} + +void +i2c_init(int speed, int slaveadd) +{ + kirkwood_i2c_hw_init(speed, slaveadd); +} + +int +i2c_read(u8 dev, uint addr, int alen, u8 *data, int length) +{ + kirkwood_i2c_msg->buf = data; + kirkwood_i2c_msg->len = length; + kirkwood_i2c_msg->addr = dev; + kirkwood_i2c_msg->flags = I2C_M_RD; + + kirkwood_i2c_prepare_for_io(kirkwood_i2c_msg); + kirkwood_i2c_doio(kirkwood_i2c_msg); + return drv_data->rc; +} + +int +i2c_write(u8 dev, uint addr, int alen, u8 *data, int length) +{ + kirkwood_i2c_msg->buf = data; + kirkwood_i2c_msg->len = length; + kirkwood_i2c_msg->addr = dev; + kirkwood_i2c_msg->flags = 0; + + kirkwood_i2c_prepare_for_io(kirkwood_i2c_msg); + kirkwood_i2c_doio(kirkwood_i2c_msg); + return drv_data->rc; +} + +int +i2c_probe(uchar chip) +{ + return i2c_read(chip, 0, 0, NULL, 0); +} + +int i2c_set_bus_num(unsigned int bus) +{ +#if defined(CONFIG_I2C_MUX) + if (bus < CONFIG_SYS_MAX_I2C_BUS) { + i2c_bus_num = bus; + } else { + int ret; + + ret = i2x_mux_select_mux(bus); + if (ret) + return ret; + i2c_bus_num = 0; + } + i2c_bus_num_mux = bus; +#else + if (bus > 0) { + return -1; + } + + i2c_bus_num = bus; +#endif + return 0; +} + +unsigned int i2c_get_bus_num(void) +{ +#if defined(CONFIG_I2C_MUX) + return i2c_bus_num_mux; +#else + return i2c_bus_num; +#endif +} + diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c index 6784603..1a4c8c9 100644 --- a/drivers/i2c/omap24xx_i2c.c +++ b/drivers/i2c/omap24xx_i2c.c @@ -31,7 +31,69 @@ static void flush_fifo(void); void i2c_init (int speed, int slaveadd) { - u16 scl; + int psc, fsscll, fssclh; + int hsscll = 0, hssclh = 0; + u32 scll, sclh; + + /* Only handle standard, fast and high speeds */ + if ((speed != OMAP_I2C_STANDARD) && + (speed != OMAP_I2C_FAST_MODE) && + (speed != OMAP_I2C_HIGH_SPEED)) { + printf("Error : I2C unsupported speed %d\n", speed); + return; + } + + psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK; + psc -= 1; + if (psc < I2C_PSC_MIN) { + printf("Error : I2C unsupported prescalar %d\n", psc); + return; + } + + if (speed == OMAP_I2C_HIGH_SPEED) { + /* High speed */ + + /* For first phase of HS mode */ + fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK / + (2 * OMAP_I2C_FAST_MODE); + + fsscll -= I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM; + fssclh -= I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM; + if (((fsscll < 0) || (fssclh < 0)) || + ((fsscll > 255) || (fssclh > 255))) { + printf("Error : I2C initializing first phase clock\n"); + return; + } + + /* For second phase of HS mode */ + hsscll = hssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed); + + hsscll -= I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM; + hssclh -= I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM; + if (((fsscll < 0) || (fssclh < 0)) || + ((fsscll > 255) || (fssclh > 255))) { + printf("Error : I2C initializing second phase clock\n"); + return; + } + + scll = (unsigned int)hsscll << 8 | (unsigned int)fsscll; + sclh = (unsigned int)hssclh << 8 | (unsigned int)fssclh; + + } else { + /* Standard and fast speed */ + fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed); + + fsscll -= I2C_FASTSPEED_SCLL_TRIM; + fssclh -= I2C_FASTSPEED_SCLH_TRIM; + if (((fsscll < 0) || (fssclh < 0)) || + ((fsscll > 255) || (fssclh > 255))) { + printf("Error : I2C initializing clock\n"); + return; + } + + scll = (unsigned int)fsscll; + sclh = (unsigned int)fssclh; + } writew(0x2, I2C_SYSC); /* for ES2 after soft reset */ udelay(1000); @@ -42,12 +104,10 @@ void i2c_init (int speed, int slaveadd) udelay (50000); } - /* 12MHz I2C module clock */ - writew (0, I2C_PSC); - speed = speed/1000; /* 100 or 400 */ - scl = ((12000/(speed*2)) - 7); /* use 7 when PSC = 0 */ - writew (scl, I2C_SCLL); - writew (scl, I2C_SCLH); + writew(psc, I2C_PSC); + writew(scll, I2C_SCLL); + writew(sclh, I2C_SCLH); + /* own address */ writew (slaveadd, I2C_OA); writew (I2C_CON_EN, I2C_CON); diff --git a/drivers/input/keyboard.c b/drivers/input/keyboard.c index 512b9f2..a5fbd5f 100644 --- a/drivers/input/keyboard.c +++ b/drivers/input/keyboard.c @@ -11,7 +11,7 @@ #include <common.h> -#include <devices.h> +#include <stdio_dev.h> #include <keyboard.h> #undef KBG_DEBUG @@ -268,7 +268,7 @@ extern int overwrite_console (void); int kbd_init (void) { int error; - device_t kbddev ; + struct stdio_dev kbddev ; char *stdinname = getenv ("stdin"); if(kbd_init_hw()==-1) @@ -281,7 +281,7 @@ int kbd_init (void) kbddev.getc = kbd_getc ; kbddev.tstc = kbd_testc ; - error = device_register (&kbddev); + error = stdio_register (&kbddev); if(error==0) { /* check if this is the standard input device */ if(strcmp(stdinname,DEVNAME)==0) { diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index ea2bf87..f6df60f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -30,6 +30,7 @@ COBJS-$(CONFIG_DS4510) += ds4510.o COBJS-$(CONFIG_FSL_LAW) += fsl_law.o COBJS-$(CONFIG_NS87308) += ns87308.o COBJS-$(CONFIG_STATUS_LED) += status_led.o +COBJS-$(CONFIG_TWL4030_LED) += twl4030_led.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/misc/twl4030_led.c b/drivers/misc/twl4030_led.c new file mode 100644 index 0000000..bfdafef --- /dev/null +++ b/drivers/misc/twl4030_led.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009 Wind River Systems, Inc. + * Tom Rix <Tom.Rix at windriver.com> + * + * 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 + * + * twl4030_led_init is from cpu/omap3/common.c, power_init_r + * + * (C) Copyright 2004-2008 + * Texas Instruments, <www.ti.com> + * + * Author : + * Sunil Kumar <sunilsaini05 at gmail.com> + * Shashi Ranjan <shashiranjanmca05 at gmail.com> + * + * Derived from Beagle Board and 3430 SDP code by + * Richard Woodruff <r-woodruff2 at ti.com> + * Syed Mohammed Khasim <khasim at ti.com> + * + */ + +#include <twl4030.h> + +#define LEDAON (0x1 << 0) +#define LEDBON (0x1 << 1) +#define LEDAPWM (0x1 << 4) +#define LEDBPWM (0x1 << 5) + +void twl4030_led_init(void) +{ + unsigned char byte; + + /* enable LED */ + byte = LEDBPWM | LEDAPWM | LEDBON | LEDAON; + + twl4030_i2c_write_u8(TWL4030_CHIP_LED, byte, + TWL4030_LED_LEDEN); + +} diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 8274af5..c6e9e6e 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -28,11 +28,13 @@ #include <config.h> #include <common.h> #include <command.h> +#include <hwconfig.h> #include <mmc.h> #include <part.h> #include <malloc.h> #include <mmc.h> #include <fsl_esdhc.h> +#include <fdt_support.h> #include <asm/io.h> @@ -346,3 +348,20 @@ int fsl_esdhc_mmc_init(bd_t *bis) { return esdhc_initialize(bis); } + +void fdt_fixup_esdhc(void *blob, bd_t *bd) +{ + const char *compat = "fsl,esdhc"; + const char *status = "okay"; + + if (!hwconfig("esdhc")) { + status = "disabled"; + goto out; + } + + do_fixup_by_compat_u32(blob, compat, "clock-frequency", + gd->sdhc_clk, 1); +out: + do_fixup_by_compat(blob, compat, "status", status, + strlen(status) + 1, 1); +} diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 8c736ce..b69ce15 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -859,6 +859,9 @@ int mmc_init(struct mmc *mmc) if (err) return err; + mmc_set_bus_width(mmc, 1); + mmc_set_clock(mmc, 1); + /* Reset the Card */ err = mmc_go_idle(mmc); diff --git a/drivers/mmc/omap3_mmc.c b/drivers/mmc/omap3_mmc.c index e90db7e..9e09434 100644 --- a/drivers/mmc/omap3_mmc.c +++ b/drivers/mmc/omap3_mmc.c @@ -28,6 +28,7 @@ #include <mmc.h> #include <part.h> #include <i2c.h> +#include <twl4030.h> #include <asm/io.h> #include <asm/arch/mmc.h> @@ -58,21 +59,11 @@ block_dev_desc_t *mmc_get_dev(int dev) return (block_dev_desc_t *) &mmc_blk_dev; } -void twl4030_mmc_config(void) -{ - unsigned char data; - - data = DEV_GRP_P1; - i2c_write(PWRMGT_ADDR_ID4, VMMC1_DEV_GRP, 1, &data, 1); - data = VMMC1_VSEL_30; - i2c_write(PWRMGT_ADDR_ID4, VMMC1_DEDICATED, 1, &data, 1); -} - unsigned char mmc_board_init(void) { t2_t *t2_base = (t2_t *)T2_BASE; - twl4030_mmc_config(); + twl4030_power_mmc_init(); writel(readl(&t2_base->pbias_lite) | PBIASLITEPWRDNZ1 | PBIASSPEEDCTRL0 | PBIASLITEPWRDNZ0, diff --git a/drivers/mtd/cfi_mtd.c b/drivers/mtd/cfi_mtd.c index c7e357b..34748dd 100644 --- a/drivers/mtd/cfi_mtd.c +++ b/drivers/mtd/cfi_mtd.c @@ -31,10 +31,17 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/concat.h> +/* use CONFIG_SYS_MAX_FLASH_BANKS_DETECT if defined */ +#ifdef CONFIG_SYS_MAX_FLASH_BANKS_DETECT +# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS_DETECT +#else +# define CFI_MAX_FLASH_BANKS CONFIG_SYS_MAX_FLASH_BANKS +#endif + extern flash_info_t flash_info[]; -static struct mtd_info cfi_mtd_info[CONFIG_SYS_MAX_FLASH_BANKS]; -static char cfi_mtd_names[CONFIG_SYS_MAX_FLASH_BANKS][16]; +static struct mtd_info cfi_mtd_info[CFI_MAX_FLASH_BANKS]; +static char cfi_mtd_names[CFI_MAX_FLASH_BANKS][16]; #ifdef CONFIG_MTD_CONCAT static char c_mtd_name[16]; #endif diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index a5680e8..89ccec2 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -26,14 +26,12 @@ include $(TOPDIR)/config.mk LIB := $(obj)libnand.a ifdef CONFIG_CMD_NAND -ifndef CONFIG_NAND_LEGACY COBJS-y += nand.o COBJS-y += nand_base.o COBJS-y += nand_bbt.o COBJS-y += nand_ecc.o COBJS-y += nand_ids.o COBJS-y += nand_util.o -endif COBJS-$(CONFIG_NAND_ATMEL) += atmel_nand.o COBJS-$(CONFIG_DRIVER_NAND_BFIN) += bfin_nand.o @@ -42,6 +40,7 @@ COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o COBJS-$(CONFIG_NAND_MPC5121_NFC) += mpc5121_nfc.o +COBJS-$(CONFIG_NAND_NDFC) += ndfc.o COBJS-$(CONFIG_NAND_NOMADIK) += nomadik.o COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index ca40c6a..7837a8e 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -182,7 +182,7 @@ static void nand_flash_init(void) * knowledge of the clocks and what devices are hooked up ... and * don't even do that unless no UBL handled it. */ -#ifdef CONFIG_SOC_DM6446 +#ifdef CONFIG_SOC_DM644X u_int32_t acfg1 = 0x3ffffffc; /*------------------------------------------------------------------* diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index e9dc4d1..edf3a099 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -19,8 +19,6 @@ #include <common.h> -#if !defined(CONFIG_NAND_LEGACY) - #include <linux/kernel.h> #include <linux/init.h> #include <linux/sched.h> @@ -1779,4 +1777,3 @@ module_exit(cleanup_nanddoc); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver\n"); -#endif diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index fc16282..694ead6 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -567,10 +567,10 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, if (len_incl_bad == *length) { rval = nand_read (nand, offset, length, buffer); - if (rval != 0) - printf ("NAND read from offset %llx failed %d\n", - offset, rval); - + if (!rval || rval == -EUCLEAN) + return 0; + printf ("NAND read from offset %llx failed %d\n", + offset, rval); return rval; } @@ -591,7 +591,7 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, read_length = nand->erasesize - block_offset; rval = nand_read (nand, offset, &read_length, p_buffer); - if (rval != 0) { + if (rval && rval != -EUCLEAN) { printf ("NAND read from offset %llx failed %d\n", offset, rval); *length -= left_to_read; diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c new file mode 100644 index 0000000..528b22b --- /dev/null +++ b/drivers/mtd/nand/ndfc.c @@ -0,0 +1,217 @@ +/* + * Overview: + * Platform independend driver for NDFC (NanD Flash Controller) + * integrated into IBM/AMCC PPC4xx cores + * + * (C) Copyright 2006-2009 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * + * Based on original work by + * Thomas Gleixner + * Copyright 2006 IBM + * + * 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 <nand.h> +#include <linux/mtd/ndfc.h> +#include <linux/mtd/nand_ecc.h> +#include <asm/processor.h> +#include <asm/io.h> +#include <ppc4xx.h> + +/* + * We need to store the info, which chip-select (CS) is used for the + * chip number. For example on Sequoia NAND chip #0 uses + * CS #3. + */ +static int ndfc_cs[NDFC_MAX_BANKS]; + +static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *this = mtd->priv; + ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; + + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) + out_8((u8 *)(base + NDFC_CMD), cmd & 0xFF); + else + out_8((u8 *)(base + NDFC_ALE), cmd & 0xFF); +} + +static int ndfc_dev_ready(struct mtd_info *mtdinfo) +{ + struct nand_chip *this = mtdinfo->priv; + ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; + + return (in_be32((u32 *)(base + NDFC_STAT)) & NDFC_STAT_IS_READY); +} + +static void ndfc_enable_hwecc(struct mtd_info *mtdinfo, int mode) +{ + struct nand_chip *this = mtdinfo->priv; + ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; + u32 ccr; + + ccr = in_be32((u32 *)(base + NDFC_CCR)); + ccr |= NDFC_CCR_RESET_ECC; + out_be32((u32 *)(base + NDFC_CCR), ccr); +} + +static int ndfc_calculate_ecc(struct mtd_info *mtdinfo, + const u_char *dat, u_char *ecc_code) +{ + struct nand_chip *this = mtdinfo->priv; + ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; + u32 ecc; + u8 *p = (u8 *)&ecc; + + ecc = in_be32((u32 *)(base + NDFC_ECC)); + + /* The NDFC uses Smart Media (SMC) bytes order + */ + ecc_code[0] = p[2]; + ecc_code[1] = p[1]; + ecc_code[2] = p[3]; + + return 0; +} + +/* + * Speedups for buffer read/write/verify + * + * NDFC allows 32bit read/write of data. So we can speed up the buffer + * functions. No further checking, as nand_base will always read/write + * page aligned. + */ +static void ndfc_read_buf(struct mtd_info *mtdinfo, uint8_t *buf, int len) +{ + struct nand_chip *this = mtdinfo->priv; + ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; + uint32_t *p = (uint32_t *) buf; + + for (;len > 0; len -= 4) + *p++ = in_be32((u32 *)(base + NDFC_DATA)); +} + +#ifndef CONFIG_NAND_SPL +/* + * Don't use these speedup functions in NAND boot image, since the image + * has to fit into 4kByte. + */ +static void ndfc_write_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len) +{ + struct nand_chip *this = mtdinfo->priv; + ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; + uint32_t *p = (uint32_t *) buf; + + for (; len > 0; len -= 4) + out_be32((u32 *)(base + NDFC_DATA), *p++); +} + +static int ndfc_verify_buf(struct mtd_info *mtdinfo, const uint8_t *buf, int len) +{ + struct nand_chip *this = mtdinfo->priv; + ulong base = (ulong) this->IO_ADDR_W & 0xffffff00; + uint32_t *p = (uint32_t *) buf; + + for (; len > 0; len -= 4) + if (*p++ != in_be32((u32 *)(base + NDFC_DATA))) + return -1; + + return 0; +} +#endif /* #ifndef CONFIG_NAND_SPL */ + +#ifndef CONFIG_SYS_NAND_BCR +#define CONFIG_SYS_NAND_BCR 0x80002222 +#endif + +void board_nand_select_device(struct nand_chip *nand, int chip) +{ + /* + * Don't use "chip" to address the NAND device, + * generate the cs from the address where it is encoded. + */ + ulong base = (ulong)nand->IO_ADDR_W & 0xffffff00; + int cs = ndfc_cs[chip]; + + /* Set NandFlash Core Configuration Register */ + /* 1 col x 2 rows */ + out_be32((u32 *)(base + NDFC_CCR), 0x00000000 | (cs << 24)); + out_be32((u32 *)(base + NDFC_BCFG0 + (cs << 2)), CONFIG_SYS_NAND_BCR); +} + +static void ndfc_select_chip(struct mtd_info *mtd, int chip) +{ + /* + * Nothing to do here! + */ +} + +int board_nand_init(struct nand_chip *nand) +{ + int cs = (ulong)nand->IO_ADDR_W & 0x00000003; + ulong base = (ulong)nand->IO_ADDR_W & 0xffffff00; + static int chip = 0; + + /* + * Save chip-select for this chip # + */ + ndfc_cs[chip] = cs; + + /* + * Select required NAND chip in NDFC + */ + board_nand_select_device(nand, chip); + + nand->IO_ADDR_R = (void __iomem *)(base + NDFC_DATA); + nand->IO_ADDR_W = (void __iomem *)(base + NDFC_DATA); + nand->cmd_ctrl = ndfc_hwcontrol; + nand->chip_delay = 50; + nand->read_buf = ndfc_read_buf; + nand->dev_ready = ndfc_dev_ready; + nand->ecc.correct = nand_correct_data; + nand->ecc.hwctl = ndfc_enable_hwecc; + nand->ecc.calculate = ndfc_calculate_ecc; + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.size = 256; + nand->ecc.bytes = 3; + nand->select_chip = ndfc_select_chip; + +#ifndef CONFIG_NAND_SPL + nand->write_buf = ndfc_write_buf; + nand->verify_buf = ndfc_verify_buf; +#else + /* + * Setup EBC (CS0 only right now) + */ + mtebc(EBC0_CFG, 0xb8400000); + + mtebc(pb0cr, CONFIG_SYS_EBC_PB0CR); + mtebc(pb0ap, CONFIG_SYS_EBC_PB0AP); +#endif + + chip++; + + return 0; +} diff --git a/drivers/mtd/nand_legacy/nand_legacy.c b/drivers/mtd/nand_legacy/nand_legacy.c deleted file mode 100644 index d9ae9c7..0000000 --- a/drivers/mtd/nand_legacy/nand_legacy.c +++ /dev/null @@ -1,1610 +0,0 @@ -/* - * (C) 2006 Denx - * Driver for NAND support, Rick Bronson - * borrowed heavily from: - * (c) 1999 Machine Vision Holdings, Inc. - * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> - * - * Added 16-bit nand support - * (C) 2004 Texas Instruments - */ - -#include <common.h> -#include <command.h> -#include <malloc.h> -#include <asm/io.h> -#include <watchdog.h> -#include <linux/mtd/nand_legacy.h> -#include <linux/mtd/nand_ids.h> -#include <jffs2/jffs2.h> - -#error Legacy NAND is deprecated. Please convert to the current NAND interface. -#error This code will be removed outright in the next release. - -#ifdef CONFIG_OMAP1510 -void archflashwp(void *archdata, int wp); -#endif - -#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1))) - -#undef PSYCHO_DEBUG -#undef NAND_DEBUG - -/* ****************** WARNING ********************* - * When ALLOW_ERASE_BAD_DEBUG is non-zero the erase command will - * erase (or at least attempt to erase) blocks that are marked - * bad. This can be very handy if you are _sure_ that the block - * is OK, say because you marked a good block bad to test bad - * block handling and you are done testing, or if you have - * accidentally marked blocks bad. - * - * Erasing factory marked bad blocks is a _bad_ idea. If the - * erase succeeds there is no reliable way to find them again, - * and attempting to program or erase bad blocks can affect - * the data in _other_ (good) blocks. - */ -#define ALLOW_ERASE_BAD_DEBUG 0 - -#define CONFIG_MTD_NAND_ECC /* enable ECC */ -#define CONFIG_MTD_NAND_ECC_JFFS2 - -/* bits for nand_legacy_rw() `cmd'; or together as needed */ -#define NANDRW_READ 0x01 -#define NANDRW_WRITE 0x00 -#define NANDRW_JFFS2 0x02 -#define NANDRW_JFFS2_SKIP 0x04 - - -/* - * Exported variables etc. - */ - -/* Definition of the out of band configuration structure */ -struct nand_oob_config { - /* position of ECC bytes inside oob */ - int ecc_pos[6]; - /* position of bad blk flag inside oob -1 = inactive */ - int badblock_pos; - /* position of ECC valid flag inside oob -1 = inactive */ - int eccvalid_pos; -} oob_config = { {0}, 0, 0}; - -struct nand_chip nand_dev_desc[CONFIG_SYS_MAX_NAND_DEVICE] = {{0}}; - -int curr_device = -1; /* Current NAND Device */ - - -/* - * Exported functionss - */ -int nand_legacy_erase(struct nand_chip* nand, size_t ofs, - size_t len, int clean); -int nand_legacy_rw(struct nand_chip* nand, int cmd, - size_t start, size_t len, - size_t * retlen, u_char * buf); -void nand_print(struct nand_chip *nand); -void nand_print_bad(struct nand_chip *nand); -int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len, - size_t * retlen, u_char * buf); -int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len, - size_t * retlen, const u_char * buf); - -/* - * Internals - */ -static int NanD_WaitReady(struct nand_chip *nand, int ale_wait); -static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len, - size_t * retlen, u_char *buf, u_char *ecc_code); -static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len, - size_t * retlen, const u_char * buf, - u_char * ecc_code); -#ifdef CONFIG_MTD_NAND_ECC -static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc); -static void nand_calculate_ecc (const u_char *dat, u_char *ecc_code); -#endif - - -/* - * - * Function definitions - * - */ - -/* returns 0 if block containing pos is OK: - * valid erase block and - * not marked bad, or no bad mark position is specified - * returns 1 if marked bad or otherwise invalid - */ -static int check_block (struct nand_chip *nand, unsigned long pos) -{ - size_t retlen; - uint8_t oob_data; - uint16_t oob_data16[6]; - int page0 = pos & (-nand->erasesize); - int page1 = page0 + nand->oobblock; - int badpos = oob_config.badblock_pos; - - if (pos >= nand->totlen) - return 1; - - if (badpos < 0) - return 0; /* no way to check, assume OK */ - - if (nand->bus16) { - if (nand_read_oob(nand, (page0 + 0), 12, &retlen, (uint8_t *)oob_data16) - || (oob_data16[2] & 0xff00) != 0xff00) - return 1; - if (nand_read_oob(nand, (page1 + 0), 12, &retlen, (uint8_t *)oob_data16) - || (oob_data16[2] & 0xff00) != 0xff00) - return 1; - } else { - /* Note - bad block marker can be on first or second page */ - if (nand_read_oob(nand, page0 + badpos, 1, &retlen, (unsigned char *)&oob_data) - || oob_data != 0xff - || nand_read_oob (nand, page1 + badpos, 1, &retlen, (unsigned char *)&oob_data) - || oob_data != 0xff) - return 1; - } - - return 0; -} - -/* print bad blocks in NAND flash */ -void nand_print_bad(struct nand_chip* nand) -{ - unsigned long pos; - - for (pos = 0; pos < nand->totlen; pos += nand->erasesize) { - if (check_block(nand, pos)) - printf(" 0x%8.8lx\n", pos); - } - puts("\n"); -} - -/* cmd: 0: NANDRW_WRITE write, fail on bad block - * 1: NANDRW_READ read, fail on bad block - * 2: NANDRW_WRITE | NANDRW_JFFS2 write, skip bad blocks - * 3: NANDRW_READ | NANDRW_JFFS2 read, data all 0xff for bad blocks - * 7: NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP read, skip bad blocks - */ -int nand_legacy_rw (struct nand_chip* nand, int cmd, - size_t start, size_t len, - size_t * retlen, u_char * buf) -{ - int ret = 0, n, total = 0; - char eccbuf[6]; - /* eblk (once set) is the start of the erase block containing the - * data being processed. - */ - unsigned long eblk = ~0; /* force mismatch on first pass */ - unsigned long erasesize = nand->erasesize; - - while (len) { - if ((start & (-erasesize)) != eblk) { - /* have crossed into new erase block, deal with - * it if it is sure marked bad. - */ - eblk = start & (-erasesize); /* start of block */ - if (check_block(nand, eblk)) { - if (cmd == (NANDRW_READ | NANDRW_JFFS2)) { - while (len > 0 && - start - eblk < erasesize) { - *(buf++) = 0xff; - ++start; - ++total; - --len; - } - continue; - } else if (cmd == (NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP)) { - start += erasesize; - continue; - } else if (cmd == (NANDRW_WRITE | NANDRW_JFFS2)) { - /* skip bad block */ - start += erasesize; - continue; - } else { - ret = 1; - break; - } - } - } - /* The ECC will not be calculated correctly if - less than 512 is written or read */ - /* Is request at least 512 bytes AND it starts on a proper boundry */ - if((start != ROUND_DOWN(start, 0x200)) || (len < 0x200)) - printf("Warning block writes should be at least 512 bytes and start on a 512 byte boundry\n"); - - if (cmd & NANDRW_READ) { - ret = nand_read_ecc(nand, start, - min(len, eblk + erasesize - start), - (size_t *)&n, (u_char*)buf, (u_char *)eccbuf); - } else { - ret = nand_write_ecc(nand, start, - min(len, eblk + erasesize - start), - (size_t *)&n, (u_char*)buf, (u_char *)eccbuf); - } - - if (ret) - break; - - start += n; - buf += n; - total += n; - len -= n; - } - if (retlen) - *retlen = total; - - return ret; -} - -void nand_print(struct nand_chip *nand) -{ - if (nand->numchips > 1) { - printf("%s at 0x%lx,\n" - "\t %d chips %s, size %d MB, \n" - "\t total size %ld MB, sector size %ld kB\n", - nand->name, nand->IO_ADDR, nand->numchips, - nand->chips_name, 1 << (nand->chipshift - 20), - nand->totlen >> 20, nand->erasesize >> 10); - } - else { - printf("%s at 0x%lx (", nand->chips_name, nand->IO_ADDR); - print_size(nand->totlen, ", "); - print_size(nand->erasesize, " sector)\n"); - } -} - -/* ------------------------------------------------------------------------- */ - -static int NanD_WaitReady(struct nand_chip *nand, int ale_wait) -{ - /* This is inline, to optimise the common case, where it's ready instantly */ - int ret = 0; - -#ifdef NAND_NO_RB /* in config file, shorter delays currently wrap accesses */ - if(ale_wait) - NAND_WAIT_READY(nand); /* do the worst case 25us wait */ - else - udelay(10); -#else /* has functional r/b signal */ - NAND_WAIT_READY(nand); -#endif - return ret; -} - -/* NanD_Command: Send a flash command to the flash chip */ - -static inline int NanD_Command(struct nand_chip *nand, unsigned char command) -{ - unsigned long nandptr = nand->IO_ADDR; - - /* Assert the CLE (Command Latch Enable) line to the flash chip */ - NAND_CTL_SETCLE(nandptr); - - /* Send the command */ - WRITE_NAND_COMMAND(command, nandptr); - - /* Lower the CLE line */ - NAND_CTL_CLRCLE(nandptr); - -#ifdef NAND_NO_RB - if(command == NAND_CMD_RESET){ - u_char ret_val; - NanD_Command(nand, NAND_CMD_STATUS); - do { - ret_val = READ_NAND(nandptr);/* wait till ready */ - } while((ret_val & 0x40) != 0x40); - } -#endif - return NanD_WaitReady(nand, 0); -} - -/* NanD_Address: Set the current address for the flash chip */ - -static int NanD_Address(struct nand_chip *nand, int numbytes, unsigned long ofs) -{ - unsigned long nandptr; - int i; - - nandptr = nand->IO_ADDR; - - /* Assert the ALE (Address Latch Enable) line to the flash chip */ - NAND_CTL_SETALE(nandptr); - - /* Send the address */ - /* Devices with 256-byte page are addressed as: - * Column (bits 0-7), Page (bits 8-15, 16-23, 24-31) - * there is no device on the market with page256 - * and more than 24 bits. - * Devices with 512-byte page are addressed as: - * Column (bits 0-7), Page (bits 9-16, 17-24, 25-31) - * 25-31 is sent only if the chip support it. - * bit 8 changes the read command to be sent - * (NAND_CMD_READ0 or NAND_CMD_READ1). - */ - - if (numbytes == ADDR_COLUMN || numbytes == ADDR_COLUMN_PAGE) - WRITE_NAND_ADDRESS(ofs, nandptr); - - ofs = ofs >> nand->page_shift; - - if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) { - for (i = 0; i < nand->pageadrlen; i++, ofs = ofs >> 8) { - WRITE_NAND_ADDRESS(ofs, nandptr); - } - } - - /* Lower the ALE line */ - NAND_CTL_CLRALE(nandptr); - - /* Wait for the chip to respond */ - return NanD_WaitReady(nand, 1); -} - -/* NanD_SelectChip: Select a given flash chip within the current floor */ - -static inline int NanD_SelectChip(struct nand_chip *nand, int chip) -{ - /* Wait for it to be ready */ - return NanD_WaitReady(nand, 0); -} - -/* NanD_IdentChip: Identify a given NAND chip given {floor,chip} */ - -static int NanD_IdentChip(struct nand_chip *nand, int floor, int chip) -{ - int mfr, id, i; - - NAND_ENABLE_CE(nand); /* set pin low */ - /* Reset the chip */ - if (NanD_Command(nand, NAND_CMD_RESET)) { -#ifdef NAND_DEBUG - printf("NanD_Command (reset) for %d,%d returned true\n", - floor, chip); -#endif - NAND_DISABLE_CE(nand); /* set pin high */ - return 0; - } - - /* Read the NAND chip ID: 1. Send ReadID command */ - if (NanD_Command(nand, NAND_CMD_READID)) { -#ifdef NAND_DEBUG - printf("NanD_Command (ReadID) for %d,%d returned true\n", - floor, chip); -#endif - NAND_DISABLE_CE(nand); /* set pin high */ - return 0; - } - - /* Read the NAND chip ID: 2. Send address byte zero */ - NanD_Address(nand, ADDR_COLUMN, 0); - - /* Read the manufacturer and device id codes from the device */ - - mfr = READ_NAND(nand->IO_ADDR); - - id = READ_NAND(nand->IO_ADDR); - - NAND_DISABLE_CE(nand); /* set pin high */ - -#ifdef NAND_DEBUG - printf("NanD_Command (ReadID) got %x %x\n", mfr, id); -#endif - if (mfr == 0xff || mfr == 0) { - /* No response - return failure */ - return 0; - } - - /* Check it's the same as the first chip we identified. - * M-Systems say that any given nand_chip device should only - * contain _one_ type of flash part, although that's not a - * hardware restriction. */ - if (nand->mfr) { - if (nand->mfr == mfr && nand->id == id) { - return 1; /* This is another the same the first */ - } else { - printf("Flash chip at floor %d, chip %d is different:\n", - floor, chip); - } - } - - /* Print and store the manufacturer and ID codes. */ - for (i = 0; nand_flash_ids[i].name != NULL; i++) { - if (mfr == nand_flash_ids[i].manufacture_id && - id == nand_flash_ids[i].model_id) { -#ifdef NAND_DEBUG - printf("Flash chip found:\n\t Manufacturer ID: 0x%2.2X, " - "Chip ID: 0x%2.2X (%s)\n", mfr, id, - nand_flash_ids[i].name); -#endif - if (!nand->mfr) { - nand->mfr = mfr; - nand->id = id; - nand->chipshift = - nand_flash_ids[i].chipshift; - nand->page256 = nand_flash_ids[i].page256; - nand->eccsize = 256; - if (nand->page256) { - nand->oobblock = 256; - nand->oobsize = 8; - nand->page_shift = 8; - } else { - nand->oobblock = 512; - nand->oobsize = 16; - nand->page_shift = 9; - } - nand->pageadrlen = nand_flash_ids[i].pageadrlen; - nand->erasesize = nand_flash_ids[i].erasesize; - nand->chips_name = nand_flash_ids[i].name; - nand->bus16 = nand_flash_ids[i].bus16; - return 1; - } - return 0; - } - } - - -#ifdef NAND_DEBUG - /* We haven't fully identified the chip. Print as much as we know. */ - printf("Unknown flash chip found: %2.2X %2.2X\n", - id, mfr); -#endif - - return 0; -} - -/* NanD_ScanChips: Find all NAND chips present in a nand_chip, and identify them */ - -static void NanD_ScanChips(struct nand_chip *nand) -{ - int floor, chip; - int numchips[NAND_MAX_FLOORS]; - int maxchips = CONFIG_SYS_NAND_MAX_CHIPS; - int ret = 1; - - nand->numchips = 0; - nand->mfr = 0; - nand->id = 0; - - - /* For each floor, find the number of valid chips it contains */ - for (floor = 0; floor < NAND_MAX_FLOORS; floor++) { - ret = 1; - numchips[floor] = 0; - for (chip = 0; chip < maxchips && ret != 0; chip++) { - - ret = NanD_IdentChip(nand, floor, chip); - if (ret) { - numchips[floor]++; - nand->numchips++; - } - } - } - - /* If there are none at all that we recognise, bail */ - if (!nand->numchips) { -#ifdef NAND_DEBUG - puts ("No NAND flash chips recognised.\n"); -#endif - return; - } - - /* Allocate an array to hold the information for each chip */ - nand->chips = malloc(sizeof(struct Nand) * nand->numchips); - if (!nand->chips) { - puts ("No memory for allocating chip info structures\n"); - return; - } - - ret = 0; - - /* Fill out the chip array with {floor, chipno} for each - * detected chip in the device. */ - for (floor = 0; floor < NAND_MAX_FLOORS; floor++) { - for (chip = 0; chip < numchips[floor]; chip++) { - nand->chips[ret].floor = floor; - nand->chips[ret].chip = chip; - nand->chips[ret].curadr = 0; - nand->chips[ret].curmode = 0x50; - ret++; - } - } - - /* Calculate and print the total size of the device */ - nand->totlen = nand->numchips * (1 << nand->chipshift); - -#ifdef NAND_DEBUG - printf("%d flash chips found. Total nand_chip size: %ld MB\n", - nand->numchips, nand->totlen >> 20); -#endif -} - -/* we need to be fast here, 1 us per read translates to 1 second per meg */ -static void NanD_ReadBuf (struct nand_chip *nand, u_char * data_buf, int cntr) -{ - unsigned long nandptr = nand->IO_ADDR; - - NanD_Command (nand, NAND_CMD_READ0); - - if (nand->bus16) { - u16 val; - - while (cntr >= 16) { - val = READ_NAND (nandptr); - *data_buf++ = val & 0xff; - *data_buf++ = val >> 8; - val = READ_NAND (nandptr); - *data_buf++ = val & 0xff; - *data_buf++ = val >> 8; - val = READ_NAND (nandptr); - *data_buf++ = val & 0xff; - *data_buf++ = val >> 8; - val = READ_NAND (nandptr); - *data_buf++ = val & 0xff; - *data_buf++ = val >> 8; - val = READ_NAND (nandptr); - *data_buf++ = val & 0xff; - *data_buf++ = val >> 8; - val = READ_NAND (nandptr); - *data_buf++ = val & 0xff; - *data_buf++ = val >> 8; - val = READ_NAND (nandptr); - *data_buf++ = val & 0xff; - *data_buf++ = val >> 8; - val = READ_NAND (nandptr); - *data_buf++ = val & 0xff; - *data_buf++ = val >> 8; - cntr -= 16; - } - - while (cntr > 0) { - val = READ_NAND (nandptr); - *data_buf++ = val & 0xff; - *data_buf++ = val >> 8; - cntr -= 2; - } - } else { - while (cntr >= 16) { - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - *data_buf++ = READ_NAND (nandptr); - cntr -= 16; - } - - while (cntr > 0) { - *data_buf++ = READ_NAND (nandptr); - cntr--; - } - } -} - -/* - * NAND read with ECC - */ -static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len, - size_t * retlen, u_char *buf, u_char *ecc_code) -{ - int col, page; - int ecc_status = 0; -#ifdef CONFIG_MTD_NAND_ECC - int j; - int ecc_failed = 0; - u_char *data_poi; - u_char ecc_calc[6]; -#endif - - /* Do not allow reads past end of device */ - if ((start + len) > nand->totlen) { - printf ("%s: Attempt read beyond end of device %x %x %x\n", - __FUNCTION__, (uint) start, (uint) len, (uint) nand->totlen); - *retlen = 0; - return -1; - } - - /* First we calculate the starting page */ - /*page = shr(start, nand->page_shift);*/ - page = start >> nand->page_shift; - - /* Get raw starting column */ - col = start & (nand->oobblock - 1); - - /* Initialize return value */ - *retlen = 0; - - /* Select the NAND device */ - NAND_ENABLE_CE(nand); /* set pin low */ - - /* Loop until all data read */ - while (*retlen < len) { - -#ifdef CONFIG_MTD_NAND_ECC - /* Do we have this page in cache ? */ - if (nand->cache_page == page) - goto readdata; - /* Send the read command */ - NanD_Command(nand, NAND_CMD_READ0); - if (nand->bus16) { - NanD_Address(nand, ADDR_COLUMN_PAGE, - (page << nand->page_shift) + (col >> 1)); - } else { - NanD_Address(nand, ADDR_COLUMN_PAGE, - (page << nand->page_shift) + col); - } - - /* Read in a page + oob data */ - NanD_ReadBuf(nand, nand->data_buf, nand->oobblock + nand->oobsize); - - /* copy data into cache, for read out of cache and if ecc fails */ - if (nand->data_cache) { - memcpy (nand->data_cache, nand->data_buf, - nand->oobblock + nand->oobsize); - } - - /* Pick the ECC bytes out of the oob data */ - for (j = 0; j < 6; j++) { - ecc_code[j] = nand->data_buf[(nand->oobblock + oob_config.ecc_pos[j])]; - } - - /* Calculate the ECC and verify it */ - /* If block was not written with ECC, skip ECC */ - if (oob_config.eccvalid_pos != -1 && - (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0x0f) != 0x0f) { - - nand_calculate_ecc (&nand->data_buf[0], &ecc_calc[0]); - switch (nand_correct_data (&nand->data_buf[0], &ecc_code[0], &ecc_calc[0])) { - case -1: - printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page); - ecc_failed++; - break; - case 1: - case 2: /* transfer ECC corrected data to cache */ - if (nand->data_cache) - memcpy (nand->data_cache, nand->data_buf, 256); - break; - } - } - - if (oob_config.eccvalid_pos != -1 && - nand->oobblock == 512 && (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0xf0) != 0xf0) { - - nand_calculate_ecc (&nand->data_buf[256], &ecc_calc[3]); - switch (nand_correct_data (&nand->data_buf[256], &ecc_code[3], &ecc_calc[3])) { - case -1: - printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page); - ecc_failed++; - break; - case 1: - case 2: /* transfer ECC corrected data to cache */ - if (nand->data_cache) - memcpy (&nand->data_cache[256], &nand->data_buf[256], 256); - break; - } - } -readdata: - /* Read the data from ECC data buffer into return buffer */ - data_poi = (nand->data_cache) ? nand->data_cache : nand->data_buf; - data_poi += col; - if ((*retlen + (nand->oobblock - col)) >= len) { - memcpy (buf + *retlen, data_poi, len - *retlen); - *retlen = len; - } else { - memcpy (buf + *retlen, data_poi, nand->oobblock - col); - *retlen += nand->oobblock - col; - } - /* Set cache page address, invalidate, if ecc_failed */ - nand->cache_page = (nand->data_cache && !ecc_failed) ? page : -1; - - ecc_status += ecc_failed; - ecc_failed = 0; - -#else - /* Send the read command */ - NanD_Command(nand, NAND_CMD_READ0); - if (nand->bus16) { - NanD_Address(nand, ADDR_COLUMN_PAGE, - (page << nand->page_shift) + (col >> 1)); - } else { - NanD_Address(nand, ADDR_COLUMN_PAGE, - (page << nand->page_shift) + col); - } - - /* Read the data directly into the return buffer */ - if ((*retlen + (nand->oobblock - col)) >= len) { - NanD_ReadBuf(nand, buf + *retlen, len - *retlen); - *retlen = len; - /* We're done */ - continue; - } else { - NanD_ReadBuf(nand, buf + *retlen, nand->oobblock - col); - *retlen += nand->oobblock - col; - } -#endif - /* For subsequent reads align to page boundary. */ - col = 0; - /* Increment page address */ - page++; - } - - /* De-select the NAND device */ - NAND_DISABLE_CE(nand); /* set pin high */ - - /* - * Return success, if no ECC failures, else -EIO - * fs driver will take care of that, because - * retlen == desired len and result == -EIO - */ - return ecc_status ? -1 : 0; -} - -/* - * Nand_page_program function is used for write and writev ! - */ -static int nand_write_page (struct nand_chip *nand, - int page, int col, int last, u_char * ecc_code) -{ - - int i; - unsigned long nandptr = nand->IO_ADDR; - -#ifdef CONFIG_MTD_NAND_ECC -#ifdef CONFIG_MTD_NAND_VERIFY_WRITE - int ecc_bytes = (nand->oobblock == 512) ? 6 : 3; -#endif -#endif - /* pad oob area */ - for (i = nand->oobblock; i < nand->oobblock + nand->oobsize; i++) - nand->data_buf[i] = 0xff; - -#ifdef CONFIG_MTD_NAND_ECC - /* Zero out the ECC array */ - for (i = 0; i < 6; i++) - ecc_code[i] = 0x00; - - /* Read back previous written data, if col > 0 */ - if (col) { - NanD_Command (nand, NAND_CMD_READ0); - if (nand->bus16) { - NanD_Address (nand, ADDR_COLUMN_PAGE, - (page << nand->page_shift) + (col >> 1)); - } else { - NanD_Address (nand, ADDR_COLUMN_PAGE, - (page << nand->page_shift) + col); - } - - if (nand->bus16) { - u16 val; - - for (i = 0; i < col; i += 2) { - val = READ_NAND (nandptr); - nand->data_buf[i] = val & 0xff; - nand->data_buf[i + 1] = val >> 8; - } - } else { - for (i = 0; i < col; i++) - nand->data_buf[i] = READ_NAND (nandptr); - } - } - - /* Calculate and write the ECC if we have enough data */ - if ((col < nand->eccsize) && (last >= nand->eccsize)) { - nand_calculate_ecc (&nand->data_buf[0], &(ecc_code[0])); - for (i = 0; i < 3; i++) { - nand->data_buf[(nand->oobblock + - oob_config.ecc_pos[i])] = ecc_code[i]; - } - if (oob_config.eccvalid_pos != -1) { - nand->data_buf[nand->oobblock + - oob_config.eccvalid_pos] = 0xf0; - } - } - - /* Calculate and write the second ECC if we have enough data */ - if ((nand->oobblock == 512) && (last == nand->oobblock)) { - nand_calculate_ecc (&nand->data_buf[256], &(ecc_code[3])); - for (i = 3; i < 6; i++) { - nand->data_buf[(nand->oobblock + - oob_config.ecc_pos[i])] = ecc_code[i]; - } - if (oob_config.eccvalid_pos != -1) { - nand->data_buf[nand->oobblock + - oob_config.eccvalid_pos] &= 0x0f; - } - } -#endif - /* Prepad for partial page programming !!! */ - for (i = 0; i < col; i++) - nand->data_buf[i] = 0xff; - - /* Postpad for partial page programming !!! oob is already padded */ - for (i = last; i < nand->oobblock; i++) - nand->data_buf[i] = 0xff; - - /* Send command to begin auto page programming */ - NanD_Command (nand, NAND_CMD_READ0); - NanD_Command (nand, NAND_CMD_SEQIN); - if (nand->bus16) { - NanD_Address (nand, ADDR_COLUMN_PAGE, - (page << nand->page_shift) + (col >> 1)); - } else { - NanD_Address (nand, ADDR_COLUMN_PAGE, - (page << nand->page_shift) + col); - } - - /* Write out complete page of data */ - if (nand->bus16) { - for (i = 0; i < (nand->oobblock + nand->oobsize); i += 2) { - WRITE_NAND (nand->data_buf[i] + - (nand->data_buf[i + 1] << 8), - nand->IO_ADDR); - } - } else { - for (i = 0; i < (nand->oobblock + nand->oobsize); i++) - WRITE_NAND (nand->data_buf[i], nand->IO_ADDR); - } - - /* Send command to actually program the data */ - NanD_Command (nand, NAND_CMD_PAGEPROG); - NanD_Command (nand, NAND_CMD_STATUS); -#ifdef NAND_NO_RB - { - u_char ret_val; - - do { - ret_val = READ_NAND (nandptr); /* wait till ready */ - } while ((ret_val & 0x40) != 0x40); - } -#endif - /* See if device thinks it succeeded */ - if (READ_NAND (nand->IO_ADDR) & 0x01) { - printf ("%s: Failed write, page 0x%08x, ", __FUNCTION__, - page); - return -1; - } -#ifdef CONFIG_MTD_NAND_VERIFY_WRITE - /* - * The NAND device assumes that it is always writing to - * a cleanly erased page. Hence, it performs its internal - * write verification only on bits that transitioned from - * 1 to 0. The device does NOT verify the whole page on a - * byte by byte basis. It is possible that the page was - * not completely erased or the page is becoming unusable - * due to wear. The read with ECC would catch the error - * later when the ECC page check fails, but we would rather - * catch it early in the page write stage. Better to write - * no data than invalid data. - */ - - /* Send command to read back the page */ - if (col < nand->eccsize) - NanD_Command (nand, NAND_CMD_READ0); - else - NanD_Command (nand, NAND_CMD_READ1); - if (nand->bus16) { - NanD_Address (nand, ADDR_COLUMN_PAGE, - (page << nand->page_shift) + (col >> 1)); - } else { - NanD_Address (nand, ADDR_COLUMN_PAGE, - (page << nand->page_shift) + col); - } - - /* Loop through and verify the data */ - if (nand->bus16) { - for (i = col; i < last; i = +2) { - if ((nand->data_buf[i] + - (nand->data_buf[i + 1] << 8)) != READ_NAND (nand->IO_ADDR)) { - printf ("%s: Failed write verify, page 0x%08x ", - __FUNCTION__, page); - return -1; - } - } - } else { - for (i = col; i < last; i++) { - if (nand->data_buf[i] != READ_NAND (nand->IO_ADDR)) { - printf ("%s: Failed write verify, page 0x%08x ", - __FUNCTION__, page); - return -1; - } - } - } - -#ifdef CONFIG_MTD_NAND_ECC - /* - * We also want to check that the ECC bytes wrote - * correctly for the same reasons stated above. - */ - NanD_Command (nand, NAND_CMD_READOOB); - if (nand->bus16) { - NanD_Address (nand, ADDR_COLUMN_PAGE, - (page << nand->page_shift) + (col >> 1)); - } else { - NanD_Address (nand, ADDR_COLUMN_PAGE, - (page << nand->page_shift) + col); - } - if (nand->bus16) { - for (i = 0; i < nand->oobsize; i += 2) { - u16 val; - - val = READ_NAND (nand->IO_ADDR); - nand->data_buf[i] = val & 0xff; - nand->data_buf[i + 1] = val >> 8; - } - } else { - for (i = 0; i < nand->oobsize; i++) { - nand->data_buf[i] = READ_NAND (nand->IO_ADDR); - } - } - for (i = 0; i < ecc_bytes; i++) { - if ((nand->data_buf[(oob_config.ecc_pos[i])] != ecc_code[i]) && ecc_code[i]) { - printf ("%s: Failed ECC write " - "verify, page 0x%08x, " - "%6i bytes were succesful\n", - __FUNCTION__, page, i); - return -1; - } - } -#endif /* CONFIG_MTD_NAND_ECC */ -#endif /* CONFIG_MTD_NAND_VERIFY_WRITE */ - return 0; -} - -static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len, - size_t * retlen, const u_char * buf, u_char * ecc_code) -{ - int i, page, col, cnt, ret = 0; - - /* Do not allow write past end of device */ - if ((to + len) > nand->totlen) { - printf ("%s: Attempt to write past end of page\n", __FUNCTION__); - return -1; - } - - /* Shift to get page */ - page = ((int) to) >> nand->page_shift; - - /* Get the starting column */ - col = to & (nand->oobblock - 1); - - /* Initialize return length value */ - *retlen = 0; - - /* Select the NAND device */ -#ifdef CONFIG_OMAP1510 - archflashwp(0,0); -#endif -#ifdef CONFIG_SYS_NAND_WP - NAND_WP_OFF(); -#endif - - NAND_ENABLE_CE(nand); /* set pin low */ - - /* Check the WP bit */ - NanD_Command(nand, NAND_CMD_STATUS); - if (!(READ_NAND(nand->IO_ADDR) & 0x80)) { - printf ("%s: Device is write protected!!!\n", __FUNCTION__); - ret = -1; - goto out; - } - - /* Loop until all data is written */ - while (*retlen < len) { - /* Invalidate cache, if we write to this page */ - if (nand->cache_page == page) - nand->cache_page = -1; - - /* Write data into buffer */ - if ((col + len) >= nand->oobblock) { - for (i = col, cnt = 0; i < nand->oobblock; i++, cnt++) { - nand->data_buf[i] = buf[(*retlen + cnt)]; - } - } else { - for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++) { - nand->data_buf[i] = buf[(*retlen + cnt)]; - } - } - /* We use the same function for write and writev !) */ - ret = nand_write_page (nand, page, col, i, ecc_code); - if (ret) - goto out; - - /* Next data start at page boundary */ - col = 0; - - /* Update written bytes count */ - *retlen += cnt; - - /* Increment page address */ - page++; - } - - /* Return happy */ - *retlen = len; - -out: - /* De-select the NAND device */ - NAND_DISABLE_CE(nand); /* set pin high */ -#ifdef CONFIG_OMAP1510 - archflashwp(0,1); -#endif -#ifdef CONFIG_SYS_NAND_WP - NAND_WP_ON(); -#endif - - return ret; -} - -/* read from the 16 bytes of oob data that correspond to a 512 byte - * page or 2 256-byte pages. - */ -int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len, - size_t * retlen, u_char * buf) -{ - int len256 = 0; - struct Nand *mychip; - int ret = 0; - - mychip = &nand->chips[ofs >> nand->chipshift]; - - /* update address for 2M x 8bit devices. OOB starts on the second */ - /* page to maintain compatibility with nand_read_ecc. */ - if (nand->page256) { - if (!(ofs & 0x8)) - ofs += 0x100; - else - ofs -= 0x8; - } - - NAND_ENABLE_CE(nand); /* set pin low */ - NanD_Command(nand, NAND_CMD_READOOB); - if (nand->bus16) { - NanD_Address(nand, ADDR_COLUMN_PAGE, - ((ofs >> nand->page_shift) << nand->page_shift) + - ((ofs & (nand->oobblock - 1)) >> 1)); - } else { - NanD_Address(nand, ADDR_COLUMN_PAGE, ofs); - } - - /* treat crossing 8-byte OOB data for 2M x 8bit devices */ - /* Note: datasheet says it should automaticaly wrap to the */ - /* next OOB block, but it didn't work here. mf. */ - if (nand->page256 && ofs + len > (ofs | 0x7) + 1) { - len256 = (ofs | 0x7) + 1 - ofs; - NanD_ReadBuf(nand, buf, len256); - - NanD_Command(nand, NAND_CMD_READOOB); - NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff)); - } - - NanD_ReadBuf(nand, &buf[len256], len - len256); - - *retlen = len; - /* Reading the full OOB data drops us off of the end of the page, - * causing the flash device to go into busy mode, so we need - * to wait until ready 11.4.1 and Toshiba TC58256FT nands */ - - ret = NanD_WaitReady(nand, 1); - NAND_DISABLE_CE(nand); /* set pin high */ - - return ret; - -} - -/* write to the 16 bytes of oob data that correspond to a 512 byte - * page or 2 256-byte pages. - */ -int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len, - size_t * retlen, const u_char * buf) -{ - int len256 = 0; - int i; - unsigned long nandptr = nand->IO_ADDR; - -#ifdef PSYCHO_DEBUG - printf("nand_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n", - (long)ofs, len, buf[0], buf[1], buf[2], buf[3], - buf[8], buf[9], buf[14],buf[15]); -#endif - - NAND_ENABLE_CE(nand); /* set pin low to enable chip */ - - /* Reset the chip */ - NanD_Command(nand, NAND_CMD_RESET); - - /* issue the Read2 command to set the pointer to the Spare Data Area. */ - NanD_Command(nand, NAND_CMD_READOOB); - if (nand->bus16) { - NanD_Address(nand, ADDR_COLUMN_PAGE, - ((ofs >> nand->page_shift) << nand->page_shift) + - ((ofs & (nand->oobblock - 1)) >> 1)); - } else { - NanD_Address(nand, ADDR_COLUMN_PAGE, ofs); - } - - /* update address for 2M x 8bit devices. OOB starts on the second */ - /* page to maintain compatibility with nand_read_ecc. */ - if (nand->page256) { - if (!(ofs & 0x8)) - ofs += 0x100; - else - ofs -= 0x8; - } - - /* issue the Serial Data In command to initial the Page Program process */ - NanD_Command(nand, NAND_CMD_SEQIN); - if (nand->bus16) { - NanD_Address(nand, ADDR_COLUMN_PAGE, - ((ofs >> nand->page_shift) << nand->page_shift) + - ((ofs & (nand->oobblock - 1)) >> 1)); - } else { - NanD_Address(nand, ADDR_COLUMN_PAGE, ofs); - } - - /* treat crossing 8-byte OOB data for 2M x 8bit devices */ - /* Note: datasheet says it should automaticaly wrap to the */ - /* next OOB block, but it didn't work here. mf. */ - if (nand->page256 && ofs + len > (ofs | 0x7) + 1) { - len256 = (ofs | 0x7) + 1 - ofs; - for (i = 0; i < len256; i++) - WRITE_NAND(buf[i], nandptr); - - NanD_Command(nand, NAND_CMD_PAGEPROG); - NanD_Command(nand, NAND_CMD_STATUS); -#ifdef NAND_NO_RB - { u_char ret_val; - do { - ret_val = READ_NAND(nandptr); /* wait till ready */ - } while ((ret_val & 0x40) != 0x40); - } -#endif - if (READ_NAND(nandptr) & 1) { - puts ("Error programming oob data\n"); - /* There was an error */ - NAND_DISABLE_CE(nand); /* set pin high */ - *retlen = 0; - return -1; - } - NanD_Command(nand, NAND_CMD_SEQIN); - NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff)); - } - - if (nand->bus16) { - for (i = len256; i < len; i += 2) { - WRITE_NAND(buf[i] + (buf[i+1] << 8), nandptr); - } - } else { - for (i = len256; i < len; i++) - WRITE_NAND(buf[i], nandptr); - } - - NanD_Command(nand, NAND_CMD_PAGEPROG); - NanD_Command(nand, NAND_CMD_STATUS); -#ifdef NAND_NO_RB - { u_char ret_val; - do { - ret_val = READ_NAND(nandptr); /* wait till ready */ - } while ((ret_val & 0x40) != 0x40); - } -#endif - if (READ_NAND(nandptr) & 1) { - puts ("Error programming oob data\n"); - /* There was an error */ - NAND_DISABLE_CE(nand); /* set pin high */ - *retlen = 0; - return -1; - } - - NAND_DISABLE_CE(nand); /* set pin high */ - *retlen = len; - return 0; - -} - -int nand_legacy_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean) -{ - /* This is defined as a structure so it will work on any system - * using native endian jffs2 (the default). - */ - static struct jffs2_unknown_node clean_marker = { - JFFS2_MAGIC_BITMASK, - JFFS2_NODETYPE_CLEANMARKER, - 8 /* 8 bytes in this node */ - }; - unsigned long nandptr; - struct Nand *mychip; - int ret = 0; - - if (ofs & (nand->erasesize-1) || len & (nand->erasesize-1)) { - printf ("Offset and size must be sector aligned, erasesize = %d\n", - (int) nand->erasesize); - return -1; - } - - nandptr = nand->IO_ADDR; - - /* Select the NAND device */ -#ifdef CONFIG_OMAP1510 - archflashwp(0,0); -#endif -#ifdef CONFIG_SYS_NAND_WP - NAND_WP_OFF(); -#endif - NAND_ENABLE_CE(nand); /* set pin low */ - - /* Check the WP bit */ - NanD_Command(nand, NAND_CMD_STATUS); - if (!(READ_NAND(nand->IO_ADDR) & 0x80)) { - printf ("nand_write_ecc: Device is write protected!!!\n"); - ret = -1; - goto out; - } - - /* Check the WP bit */ - NanD_Command(nand, NAND_CMD_STATUS); - if (!(READ_NAND(nand->IO_ADDR) & 0x80)) { - printf ("%s: Device is write protected!!!\n", __FUNCTION__); - ret = -1; - goto out; - } - - /* FIXME: Do nand in the background. Use timers or schedule_task() */ - while(len) { - /*mychip = &nand->chips[shr(ofs, nand->chipshift)];*/ - mychip = &nand->chips[ofs >> nand->chipshift]; - - /* always check for bad block first, genuine bad blocks - * should _never_ be erased. - */ - if (ALLOW_ERASE_BAD_DEBUG || !check_block(nand, ofs)) { - /* Select the NAND device */ - NAND_ENABLE_CE(nand); /* set pin low */ - - NanD_Command(nand, NAND_CMD_ERASE1); - NanD_Address(nand, ADDR_PAGE, ofs); - NanD_Command(nand, NAND_CMD_ERASE2); - - NanD_Command(nand, NAND_CMD_STATUS); - -#ifdef NAND_NO_RB - { u_char ret_val; - do { - ret_val = READ_NAND(nandptr); /* wait till ready */ - } while ((ret_val & 0x40) != 0x40); - } -#endif - if (READ_NAND(nandptr) & 1) { - printf ("%s: Error erasing at 0x%lx\n", - __FUNCTION__, (long)ofs); - /* There was an error */ - ret = -1; - goto out; - } - if (clean) { - int n; /* return value not used */ - int p, l; - - /* clean marker position and size depend - * on the page size, since 256 byte pages - * only have 8 bytes of oob data - */ - if (nand->page256) { - p = NAND_JFFS2_OOB8_FSDAPOS; - l = NAND_JFFS2_OOB8_FSDALEN; - } else { - p = NAND_JFFS2_OOB16_FSDAPOS; - l = NAND_JFFS2_OOB16_FSDALEN; - } - - ret = nand_write_oob(nand, ofs + p, l, (size_t *)&n, - (u_char *)&clean_marker); - /* quit here if write failed */ - if (ret) - goto out; - } - } - ofs += nand->erasesize; - len -= nand->erasesize; - } - -out: - /* De-select the NAND device */ - NAND_DISABLE_CE(nand); /* set pin high */ -#ifdef CONFIG_OMAP1510 - archflashwp(0,1); -#endif -#ifdef CONFIG_SYS_NAND_WP - NAND_WP_ON(); -#endif - - return ret; -} - - -static inline int nandcheck(unsigned long potential, unsigned long physadr) -{ - return 0; -} - -unsigned long nand_probe(unsigned long physadr) -{ - struct nand_chip *nand = NULL; - int i = 0, ChipID = 1; - -#ifdef CONFIG_MTD_NAND_ECC_JFFS2 - oob_config.ecc_pos[0] = NAND_JFFS2_OOB_ECCPOS0; - oob_config.ecc_pos[1] = NAND_JFFS2_OOB_ECCPOS1; - oob_config.ecc_pos[2] = NAND_JFFS2_OOB_ECCPOS2; - oob_config.ecc_pos[3] = NAND_JFFS2_OOB_ECCPOS3; - oob_config.ecc_pos[4] = NAND_JFFS2_OOB_ECCPOS4; - oob_config.ecc_pos[5] = NAND_JFFS2_OOB_ECCPOS5; - oob_config.eccvalid_pos = 4; -#else - oob_config.ecc_pos[0] = NAND_NOOB_ECCPOS0; - oob_config.ecc_pos[1] = NAND_NOOB_ECCPOS1; - oob_config.ecc_pos[2] = NAND_NOOB_ECCPOS2; - oob_config.ecc_pos[3] = NAND_NOOB_ECCPOS3; - oob_config.ecc_pos[4] = NAND_NOOB_ECCPOS4; - oob_config.ecc_pos[5] = NAND_NOOB_ECCPOS5; - oob_config.eccvalid_pos = NAND_NOOB_ECCVPOS; -#endif - oob_config.badblock_pos = 5; - - for (i=0; i<CONFIG_SYS_MAX_NAND_DEVICE; i++) { - if (nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN) { - nand = &nand_dev_desc[i]; - break; - } - } - if (!nand) - return (0); - - memset((char *)nand, 0, sizeof(struct nand_chip)); - - nand->IO_ADDR = physadr; - nand->cache_page = -1; /* init the cache page */ - NanD_ScanChips(nand); - - if (nand->totlen == 0) { - /* no chips found, clean up and quit */ - memset((char *)nand, 0, sizeof(struct nand_chip)); - nand->ChipID = NAND_ChipID_UNKNOWN; - return (0); - } - - nand->ChipID = ChipID; - if (curr_device == -1) - curr_device = i; - - nand->data_buf = malloc (nand->oobblock + nand->oobsize); - if (!nand->data_buf) { - puts ("Cannot allocate memory for data structures.\n"); - return (0); - } - - return (nand->totlen); -} - -#ifdef CONFIG_MTD_NAND_ECC -/* - * Pre-calculated 256-way 1 byte column parity - */ -static const u_char nand_ecc_precalc_table[] = { - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, - 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, - 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, - 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, - 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, - 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, - 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, - 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, - 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, - 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, - 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, - 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, - 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, - 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, - 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, - 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, - 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 -}; - - -/* - * Creates non-inverted ECC code from line parity - */ -static void nand_trans_result(u_char reg2, u_char reg3, - u_char *ecc_code) -{ - u_char a, b, i, tmp1, tmp2; - - /* Initialize variables */ - a = b = 0x80; - tmp1 = tmp2 = 0; - - /* Calculate first ECC byte */ - for (i = 0; i < 4; i++) { - if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */ - tmp1 |= b; - b >>= 1; - if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */ - tmp1 |= b; - b >>= 1; - a >>= 1; - } - - /* Calculate second ECC byte */ - b = 0x80; - for (i = 0; i < 4; i++) { - if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */ - tmp2 |= b; - b >>= 1; - if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */ - tmp2 |= b; - b >>= 1; - a >>= 1; - } - - /* Store two of the ECC bytes */ - ecc_code[0] = tmp1; - ecc_code[1] = tmp2; -} - -/* - * Calculate 3 byte ECC code for 256 byte block - */ -static void nand_calculate_ecc (const u_char *dat, u_char *ecc_code) -{ - u_char idx, reg1, reg3; - int j; - - /* Initialize variables */ - reg1 = reg3 = 0; - ecc_code[0] = ecc_code[1] = ecc_code[2] = 0; - - /* Build up column parity */ - for(j = 0; j < 256; j++) { - - /* Get CP0 - CP5 from table */ - idx = nand_ecc_precalc_table[dat[j]]; - reg1 ^= idx; - - /* All bit XOR = 1 ? */ - if (idx & 0x40) { - reg3 ^= (u_char) j; - } - } - - /* Create non-inverted ECC code from line parity */ - nand_trans_result((reg1 & 0x40) ? ~reg3 : reg3, reg3, ecc_code); - - /* Calculate final ECC code */ - ecc_code[0] = ~ecc_code[0]; - ecc_code[1] = ~ecc_code[1]; - ecc_code[2] = ((~reg1) << 2) | 0x03; -} - -/* - * Detect and correct a 1 bit error for 256 byte block - */ -static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc) -{ - u_char a, b, c, d1, d2, d3, add, bit, i; - - /* Do error detection */ - d1 = calc_ecc[0] ^ read_ecc[0]; - d2 = calc_ecc[1] ^ read_ecc[1]; - d3 = calc_ecc[2] ^ read_ecc[2]; - - if ((d1 | d2 | d3) == 0) { - /* No errors */ - return 0; - } else { - a = (d1 ^ (d1 >> 1)) & 0x55; - b = (d2 ^ (d2 >> 1)) & 0x55; - c = (d3 ^ (d3 >> 1)) & 0x54; - - /* Found and will correct single bit error in the data */ - if ((a == 0x55) && (b == 0x55) && (c == 0x54)) { - c = 0x80; - add = 0; - a = 0x80; - for (i=0; i<4; i++) { - if (d1 & c) - add |= a; - c >>= 2; - a >>= 1; - } - c = 0x80; - for (i=0; i<4; i++) { - if (d2 & c) - add |= a; - c >>= 2; - a >>= 1; - } - bit = 0; - b = 0x04; - c = 0x80; - for (i=0; i<3; i++) { - if (d3 & c) - bit |= b; - c >>= 2; - b >>= 1; - } - b = 0x01; - a = dat[add]; - a ^= (b << bit); - dat[add] = a; - return 1; - } - else { - i = 0; - while (d1) { - if (d1 & 0x01) - ++i; - d1 >>= 1; - } - while (d2) { - if (d2 & 0x01) - ++i; - d2 >>= 1; - } - while (d3) { - if (d3 & 0x01) - ++i; - d3 >>= 1; - } - if (i == 1) { - /* ECC Code Error Correction */ - read_ecc[0] = calc_ecc[0]; - read_ecc[1] = calc_ecc[1]; - read_ecc[2] = calc_ecc[2]; - return 2; - } - else { - /* Uncorrectable Error */ - return -1; - } - } - } - - /* Should never happen */ - return -1; -} - -#endif - -#ifdef CONFIG_JFFS2_NAND -int read_jffs2_nand(size_t start, size_t len, - size_t * retlen, u_char * buf, int nanddev) -{ - return nand_legacy_rw(nand_dev_desc + nanddev, NANDRW_READ | NANDRW_JFFS2, - start, len, retlen, buf); -} -#endif /* CONFIG_JFFS2_NAND */ diff --git a/drivers/net/4xx_enet.c b/drivers/net/4xx_enet.c index 587605d..c020048 100644 --- a/drivers/net/4xx_enet.c +++ b/drivers/net/4xx_enet.c @@ -870,7 +870,7 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis) defined(CONFIG_405EX) u32 opbfreq; sys_info_t sysinfo; -#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \ +#if defined(CONFIG_440GX) || \ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \ defined(CONFIG_405EX) @@ -1119,7 +1119,6 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis) #if defined(CONFIG_440GX) || \ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ - defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \ defined(CONFIG_460EX) || defined(CONFIG_460GT) || \ defined(CONFIG_405EX) diff --git a/drivers/net/Makefile b/drivers/net/Makefile index c6097c3..34b56d8 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -37,6 +37,7 @@ COBJS-$(CONFIG_DNET) += dnet.o COBJS-$(CONFIG_E1000) += e1000.o COBJS-$(CONFIG_EEPRO100) += eepro100.o COBJS-$(CONFIG_ENC28J60) += enc28j60.o +COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o COBJS-$(CONFIG_GRETH) += greth.o COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o @@ -63,7 +64,7 @@ COBJS-$(CONFIG_RTL8169) += rtl8169.o COBJS-$(CONFIG_DRIVER_S3C4510_ETH) += s3c4510b_eth.o COBJS-$(CONFIG_SH_ETHER) += sh_eth.o COBJS-$(CONFIG_DRIVER_SMC91111) += smc91111.o -COBJS-$(CONFIG_DRIVER_SMC911X) += smc911x.o +COBJS-$(CONFIG_SMC911X) += smc911x.o COBJS-$(CONFIG_TIGON3) += tigon3.o bcm570x_autoneg.o 5701rls.o COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o COBJS-$(CONFIG_TSEC_ENET) += tsec.o diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c new file mode 100644 index 0000000..bd83a24 --- /dev/null +++ b/drivers/net/fec_mxc.c @@ -0,0 +1,741 @@ +/* + * (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com> + * (C) Copyright 2008,2009 Eric Jarrige <eric.jarrige@armadeus.org> + * (C) Copyright 2008 Armadeus Systems nc + * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> + * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de> + * + * 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 <malloc.h> +#include <net.h> +#include <miiphy.h> +#include "fec_mxc.h" + +#include <asm/arch/clock.h> +#include <asm/arch/imx-regs.h> +#include <asm/io.h> +#include <asm/errno.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_MII +#error "CONFIG_MII has to be defined!" +#endif + +#undef DEBUG + +struct nbuf { + uint8_t data[1500]; /**< actual data */ + int length; /**< actual length */ + int used; /**< buffer in use or not */ + uint8_t head[16]; /**< MAC header(6 + 6 + 2) + 2(aligned) */ +}; + +struct fec_priv gfec = { + .eth = (struct ethernet_regs *)IMX_FEC_BASE, + .xcv_type = MII100, + .rbd_base = NULL, + .rbd_index = 0, + .tbd_base = NULL, + .tbd_index = 0, + .bd = NULL, +}; + +/* + * MII-interface related functions + */ +static int fec_miiphy_read(char *dev, uint8_t phyAddr, uint8_t regAddr, + uint16_t *retVal) +{ + struct eth_device *edev = eth_get_dev_by_name(dev); + struct fec_priv *fec = (struct fec_priv *)edev->priv; + + uint32_t reg; /* convenient holder for the PHY register */ + uint32_t phy; /* convenient holder for the PHY */ + uint32_t start; + + /* + * reading from any PHY's register is done by properly + * programming the FEC's MII data register. + */ + writel(FEC_IEVENT_MII, &fec->eth->ievent); + reg = regAddr << FEC_MII_DATA_RA_SHIFT; + phy = phyAddr << FEC_MII_DATA_PA_SHIFT; + + writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA | + phy | reg, &fec->eth->mii_data); + + /* + * wait for the related interrupt + */ + start = get_timer_masked(); + while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) { + if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) { + printf("Read MDIO failed...\n"); + return -1; + } + } + + /* + * clear mii interrupt bit + */ + writel(FEC_IEVENT_MII, &fec->eth->ievent); + + /* + * it's now safe to read the PHY's register + */ + *retVal = readl(&fec->eth->mii_data); + debug("fec_miiphy_read: phy: %02x reg:%02x val:%#x\n", phyAddr, + regAddr, *retVal); + return 0; +} + +static int fec_miiphy_write(char *dev, uint8_t phyAddr, uint8_t regAddr, + uint16_t data) +{ + struct eth_device *edev = eth_get_dev_by_name(dev); + struct fec_priv *fec = (struct fec_priv *)edev->priv; + + uint32_t reg; /* convenient holder for the PHY register */ + uint32_t phy; /* convenient holder for the PHY */ + uint32_t start; + + reg = regAddr << FEC_MII_DATA_RA_SHIFT; + phy = phyAddr << FEC_MII_DATA_PA_SHIFT; + + writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | + FEC_MII_DATA_TA | phy | reg | data, &fec->eth->mii_data); + + /* + * wait for the MII interrupt + */ + start = get_timer_masked(); + while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) { + if (get_timer(start) > (CONFIG_SYS_HZ / 1000)) { + printf("Write MDIO failed...\n"); + return -1; + } + } + + /* + * clear MII interrupt bit + */ + writel(FEC_IEVENT_MII, &fec->eth->ievent); + debug("fec_miiphy_write: phy: %02x reg:%02x val:%#x\n", phyAddr, + regAddr, data); + + return 0; +} + +static int miiphy_restart_aneg(struct eth_device *dev) +{ + /* + * Wake up from sleep if necessary + * Reset PHY, then delay 300ns + */ + miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_MIPGSR, 0x00FF); + miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_BMCR, + PHY_BMCR_RESET); + udelay(1000); + + /* + * Set the auto-negotiation advertisement register bits + */ + miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_ANAR, 0x1e0); + miiphy_write(dev->name, CONFIG_FEC_MXC_PHYADDR, PHY_BMCR, + PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); + + return 0; +} + +static int miiphy_wait_aneg(struct eth_device *dev) +{ + uint32_t start; + uint16_t status; + + /* + * Wait for AN completion + */ + start = get_timer_masked(); + do { + if (get_timer(start) > (CONFIG_SYS_HZ * 5)) { + printf("%s: Autonegotiation timeout\n", dev->name); + return -1; + } + + if (miiphy_read(dev->name, CONFIG_FEC_MXC_PHYADDR, + PHY_BMSR, &status)) { + printf("%s: Autonegotiation failed. status: 0x%04x\n", + dev->name, status); + return -1; + } + } while (!(status & PHY_BMSR_LS)); + + return 0; +} +static int fec_rx_task_enable(struct fec_priv *fec) +{ + writel(1 << 24, &fec->eth->r_des_active); + return 0; +} + +static int fec_rx_task_disable(struct fec_priv *fec) +{ + return 0; +} + +static int fec_tx_task_enable(struct fec_priv *fec) +{ + writel(1 << 24, &fec->eth->x_des_active); + return 0; +} + +static int fec_tx_task_disable(struct fec_priv *fec) +{ + return 0; +} + +/** + * Initialize receive task's buffer descriptors + * @param[in] fec all we know about the device yet + * @param[in] count receive buffer count to be allocated + * @param[in] size size of each receive buffer + * @return 0 on success + * + * For this task we need additional memory for the data buffers. And each + * data buffer requires some alignment. Thy must be aligned to a specific + * boundary each (DB_DATA_ALIGNMENT). + */ +static int fec_rbd_init(struct fec_priv *fec, int count, int size) +{ + int ix; + uint32_t p = 0; + + /* reserve data memory and consider alignment */ + fec->rdb_ptr = malloc(size * count + DB_DATA_ALIGNMENT); + p = (uint32_t)fec->rdb_ptr; + if (!p) { + puts("fec_imx27: not enough malloc memory!\n"); + return -ENOMEM; + } + memset((void *)p, 0, size * count + DB_DATA_ALIGNMENT); + p += DB_DATA_ALIGNMENT-1; + p &= ~(DB_DATA_ALIGNMENT-1); + + for (ix = 0; ix < count; ix++) { + writel(p, &fec->rbd_base[ix].data_pointer); + p += size; + writew(FEC_RBD_EMPTY, &fec->rbd_base[ix].status); + writew(0, &fec->rbd_base[ix].data_length); + } + /* + * mark the last RBD to close the ring + */ + writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &fec->rbd_base[ix - 1].status); + fec->rbd_index = 0; + + return 0; +} + +/** + * Initialize transmit task's buffer descriptors + * @param[in] fec all we know about the device yet + * + * Transmit buffers are created externally. We only have to init the BDs here.\n + * Note: There is a race condition in the hardware. When only one BD is in + * use it must be marked with the WRAP bit to use it for every transmitt. + * This bit in combination with the READY bit results into double transmit + * of each data buffer. It seems the state machine checks READY earlier then + * resetting it after the first transfer. + * Using two BDs solves this issue. + */ +static void fec_tbd_init(struct fec_priv *fec) +{ + writew(0x0000, &fec->tbd_base[0].status); + writew(FEC_TBD_WRAP, &fec->tbd_base[1].status); + fec->tbd_index = 0; +} + +/** + * Mark the given read buffer descriptor as free + * @param[in] last 1 if this is the last buffer descriptor in the chain, else 0 + * @param[in] pRbd buffer descriptor to mark free again + */ +static void fec_rbd_clean(int last, struct fec_bd *pRbd) +{ + /* + * Reset buffer descriptor as empty + */ + if (last) + writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &pRbd->status); + else + writew(FEC_RBD_EMPTY, &pRbd->status); + /* + * no data in it + */ + writew(0, &pRbd->data_length); +} + +static int fec_get_hwaddr(struct eth_device *dev, unsigned char *mac) +{ + struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; + int i; + + for (i = 0; i < 6; i++) + mac[6-1-i] = readl(&iim->iim_bank_area0[IIM0_MAC + i]); + + return is_valid_ether_addr(mac); +} + +static int fec_set_hwaddr(struct eth_device *dev, unsigned char *mac) +{ + struct fec_priv *fec = (struct fec_priv *)dev->priv; + + writel(0, &fec->eth->iaddr1); + writel(0, &fec->eth->iaddr2); + writel(0, &fec->eth->gaddr1); + writel(0, &fec->eth->gaddr2); + + /* + * Set physical address + */ + writel((mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3], + &fec->eth->paddr1); + writel((mac[4] << 24) + (mac[5] << 16) + 0x8808, &fec->eth->paddr2); + + return 0; +} + +/** + * Start the FEC engine + * @param[in] dev Our device to handle + */ +static int fec_open(struct eth_device *edev) +{ + struct fec_priv *fec = (struct fec_priv *)edev->priv; + + debug("fec_open: fec_open(dev)\n"); + /* full-duplex, heartbeat disabled */ + writel(1 << 2, &fec->eth->x_cntrl); + fec->rbd_index = 0; + + /* + * Enable FEC-Lite controller + */ + writel(FEC_ECNTRL_ETHER_EN, &fec->eth->ecntrl); + + miiphy_wait_aneg(edev); + miiphy_speed(edev->name, 0); + miiphy_duplex(edev->name, 0); + + /* + * Enable SmartDMA receive task + */ + fec_rx_task_enable(fec); + + udelay(100000); + return 0; +} + +static int fec_init(struct eth_device *dev, bd_t* bd) +{ + uint32_t base; + struct fec_priv *fec = (struct fec_priv *)dev->priv; + + /* + * reserve memory for both buffer descriptor chains at once + * Datasheet forces the startaddress of each chain is 16 byte + * aligned + */ + fec->base_ptr = malloc((2 + FEC_RBD_NUM) * + sizeof(struct fec_bd) + DB_ALIGNMENT); + base = (uint32_t)fec->base_ptr; + if (!base) { + puts("fec_imx27: not enough malloc memory!\n"); + return -ENOMEM; + } + memset((void *)base, 0, (2 + FEC_RBD_NUM) * + sizeof(struct fec_bd) + DB_ALIGNMENT); + base += (DB_ALIGNMENT-1); + base &= ~(DB_ALIGNMENT-1); + + fec->rbd_base = (struct fec_bd *)base; + + base += FEC_RBD_NUM * sizeof(struct fec_bd); + + fec->tbd_base = (struct fec_bd *)base; + + /* + * Set interrupt mask register + */ + writel(0x00000000, &fec->eth->imask); + + /* + * Clear FEC-Lite interrupt event register(IEVENT) + */ + writel(0xffffffff, &fec->eth->ievent); + + + /* + * Set FEC-Lite receive control register(R_CNTRL): + */ + if (fec->xcv_type == SEVENWIRE) { + /* + * Frame length=1518; 7-wire mode + */ + writel(0x05ee0020, &fec->eth->r_cntrl); /* FIXME 0x05ee0000 */ + } else { + /* + * Frame length=1518; MII mode; + */ + writel(0x05ee0024, &fec->eth->r_cntrl); /* FIXME 0x05ee0004 */ + /* + * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock + * and do not drop the Preamble. + */ + writel((((imx_get_ahbclk() / 1000000) + 2) / 5) << 1, + &fec->eth->mii_speed); + debug("fec_init: mii_speed %#lx\n", + (((imx_get_ahbclk() / 1000000) + 2) / 5) << 1); + } + /* + * Set Opcode/Pause Duration Register + */ + writel(0x00010020, &fec->eth->op_pause); /* FIXME 0xffff0020; */ + writel(0x2, &fec->eth->x_wmrk); + /* + * Set multicast address filter + */ + writel(0x00000000, &fec->eth->gaddr1); + writel(0x00000000, &fec->eth->gaddr2); + + + /* clear MIB RAM */ + long *mib_ptr = (long *)(IMX_FEC_BASE + 0x200); + while (mib_ptr <= (long *)(IMX_FEC_BASE + 0x2FC)) + *mib_ptr++ = 0; + + /* FIFO receive start register */ + writel(0x520, &fec->eth->r_fstart); + + /* size and address of each buffer */ + writel(FEC_MAX_PKT_SIZE, &fec->eth->emrbr); + writel((uint32_t)fec->tbd_base, &fec->eth->etdsr); + writel((uint32_t)fec->rbd_base, &fec->eth->erdsr); + + /* + * Initialize RxBD/TxBD rings + */ + if (fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE) < 0) { + free(fec->base_ptr); + return -ENOMEM; + } + fec_tbd_init(fec); + + + if (fec->xcv_type != SEVENWIRE) + miiphy_restart_aneg(dev); + + fec_open(dev); + return 0; +} + +/** + * Halt the FEC engine + * @param[in] dev Our device to handle + */ +static void fec_halt(struct eth_device *dev) +{ + struct fec_priv *fec = &gfec; + int counter = 0xffff; + + /* + * issue graceful stop command to the FEC transmitter if necessary + */ + writel(FEC_ECNTRL_RESET | readl(&fec->eth->x_cntrl), + &fec->eth->x_cntrl); + + debug("eth_halt: wait for stop regs\n"); + /* + * wait for graceful stop to register + */ + while ((counter--) && (!(readl(&fec->eth->ievent) & FEC_IEVENT_GRA))) + ; /* FIXME ensure time */ + + /* + * Disable SmartDMA tasks + */ + fec_tx_task_disable(fec); + fec_rx_task_disable(fec); + + /* + * Disable the Ethernet Controller + * Note: this will also reset the BD index counter! + */ + writel(0, &fec->eth->ecntrl); + fec->rbd_index = 0; + fec->tbd_index = 0; + free(fec->rdb_ptr); + free(fec->base_ptr); + debug("eth_halt: done\n"); +} + +/** + * Transmit one frame + * @param[in] dev Our ethernet device to handle + * @param[in] packet Pointer to the data to be transmitted + * @param[in] length Data count in bytes + * @return 0 on success + */ +static int fec_send(struct eth_device *dev, volatile void* packet, int length) +{ + unsigned int status; + + /* + * This routine transmits one frame. This routine only accepts + * 6-byte Ethernet addresses. + */ + struct fec_priv *fec = (struct fec_priv *)dev->priv; + + /* + * Check for valid length of data. + */ + if ((length > 1500) || (length <= 0)) { + printf("Payload (%d) to large!\n", length); + return -1; + } + + /* + * Setup the transmit buffer + * Note: We are always using the first buffer for transmission, + * the second will be empty and only used to stop the DMA engine + */ + writew(length, &fec->tbd_base[fec->tbd_index].data_length); + writel((uint32_t)packet, &fec->tbd_base[fec->tbd_index].data_pointer); + /* + * update BD's status now + * This block: + * - is always the last in a chain (means no chain) + * - should transmitt the CRC + * - might be the last BD in the list, so the address counter should + * wrap (-> keep the WRAP flag) + */ + status = readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_WRAP; + status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY; + writew(status, &fec->tbd_base[fec->tbd_index].status); + + /* + * Enable SmartDMA transmit task + */ + fec_tx_task_enable(fec); + + /* + * wait until frame is sent . + */ + while (readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_READY) { + /* FIXME: Timeout */ + } + debug("fec_send: status 0x%x index %d\n", + readw(&fec->tbd_base[fec->tbd_index].status), + fec->tbd_index); + /* for next transmission use the other buffer */ + if (fec->tbd_index) + fec->tbd_index = 0; + else + fec->tbd_index = 1; + + return 0; +} + +/** + * Pull one frame from the card + * @param[in] dev Our ethernet device to handle + * @return Length of packet read + */ +static int fec_recv(struct eth_device *dev) +{ + struct fec_priv *fec = (struct fec_priv *)dev->priv; + struct fec_bd *rbd = &fec->rbd_base[fec->rbd_index]; + unsigned long ievent; + int frame_length, len = 0; + struct nbuf *frame; + uint16_t bd_status; + uchar buff[FEC_MAX_PKT_SIZE]; + + /* + * Check if any critical events have happened + */ + ievent = readl(&fec->eth->ievent); + writel(ievent, &fec->eth->ievent); + debug("fec_recv: ievent 0x%x\n", ievent); + if (ievent & FEC_IEVENT_BABR) { + fec_halt(dev); + fec_init(dev, fec->bd); + printf("some error: 0x%08lx\n", ievent); + return 0; + } + if (ievent & FEC_IEVENT_HBERR) { + /* Heartbeat error */ + writel(0x00000001 | readl(&fec->eth->x_cntrl), + &fec->eth->x_cntrl); + } + if (ievent & FEC_IEVENT_GRA) { + /* Graceful stop complete */ + if (readl(&fec->eth->x_cntrl) & 0x00000001) { + fec_halt(dev); + writel(~0x00000001 & readl(&fec->eth->x_cntrl), + &fec->eth->x_cntrl); + fec_init(dev, fec->bd); + } + } + + /* + * ensure reading the right buffer status + */ + bd_status = readw(&rbd->status); + debug("fec_recv: status 0x%x\n", bd_status); + + if (!(bd_status & FEC_RBD_EMPTY)) { + if ((bd_status & FEC_RBD_LAST) && !(bd_status & FEC_RBD_ERR) && + ((readw(&rbd->data_length) - 4) > 14)) { + /* + * Get buffer address and size + */ + frame = (struct nbuf *)readl(&rbd->data_pointer); + frame_length = readw(&rbd->data_length) - 4; + /* + * Fill the buffer and pass it to upper layers + */ + memcpy(buff, frame->data, frame_length); + NetReceive(buff, frame_length); + len = frame_length; + } else { + if (bd_status & FEC_RBD_ERR) + printf("error frame: 0x%08lx 0x%08x\n", + (ulong)rbd->data_pointer, + bd_status); + } + /* + * free the current buffer, restart the engine + * and move forward to the next buffer + */ + fec_rbd_clean(fec->rbd_index == (FEC_RBD_NUM - 1) ? 1 : 0, rbd); + fec_rx_task_enable(fec); + fec->rbd_index = (fec->rbd_index + 1) % FEC_RBD_NUM; + } + debug("fec_recv: stop\n"); + + return len; +} + +static int fec_probe(bd_t *bd) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + struct eth_device *edev; + struct fec_priv *fec = &gfec; + unsigned char ethaddr_str[20]; + unsigned char ethaddr[6]; + char *tmp = getenv("ethaddr"); + char *end; + + /* enable FEC clock */ + writel(readl(&pll->pccr1) | PCCR1_HCLK_FEC, &pll->pccr1); + writel(readl(&pll->pccr0) | PCCR0_FEC_EN, &pll->pccr0); + + /* create and fill edev struct */ + edev = (struct eth_device *)malloc(sizeof(struct eth_device)); + if (!edev) { + puts("fec_imx27: not enough malloc memory!\n"); + return -ENOMEM; + } + edev->priv = fec; + edev->init = fec_init; + edev->send = fec_send; + edev->recv = fec_recv; + edev->halt = fec_halt; + + fec->eth = (struct ethernet_regs *)IMX_FEC_BASE; + fec->bd = bd; + + fec->xcv_type = MII100; + + /* Reset chip. */ + writel(FEC_ECNTRL_RESET, &fec->eth->ecntrl); + while (readl(&fec->eth->ecntrl) & 1) + udelay(10); + + /* + * Set interrupt mask register + */ + writel(0x00000000, &fec->eth->imask); + + /* + * Clear FEC-Lite interrupt event register(IEVENT) + */ + writel(0xffffffff, &fec->eth->ievent); + + /* + * Set FEC-Lite receive control register(R_CNTRL): + */ + /* + * Frame length=1518; MII mode; + */ + writel(0x05ee0024, &fec->eth->r_cntrl); /* FIXME 0x05ee0004 */ + /* + * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock + * and do not drop the Preamble. + */ + writel((((imx_get_ahbclk() / 1000000) + 2) / 5) << 1, + &fec->eth->mii_speed); + debug("fec_init: mii_speed %#lx\n", + (((imx_get_ahbclk() / 1000000) + 2) / 5) << 1); + + sprintf(edev->name, "FEC_MXC"); + + miiphy_register(edev->name, fec_miiphy_read, fec_miiphy_write); + + eth_register(edev); + + if ((NULL != tmp) && (12 <= strlen(tmp))) { + int i; + /* convert MAC from string to int */ + for (i = 0; i < 6; i++) { + ethaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0; + if (tmp) + tmp = (*end) ? end + 1 : end; + } + } else if (fec_get_hwaddr(edev, ethaddr) == 0) { + printf("got MAC address from EEPROM: %pM\n", ethaddr); + setenv("ethaddr", (char *)ethaddr_str); + } + memcpy(edev->enetaddr, ethaddr, 6); + fec_set_hwaddr(edev, ethaddr); + + return 0; +} + +int fecmxc_initialize(bd_t *bd) +{ + int lout = 1; + + debug("eth_init: fec_probe(bd)\n"); + lout = fec_probe(bd); + + return lout; +} diff --git a/drivers/net/fec_mxc.h b/drivers/net/fec_mxc.h new file mode 100644 index 0000000..6cb1bfc --- /dev/null +++ b/drivers/net/fec_mxc.h @@ -0,0 +1,304 @@ +/* + * (C) Copyright 2009 Ilya Yanok, Emcraft Systems Ltd <yanok@emcraft.com> + * (C) Copyright 2008 Armadeus Systems, nc + * (C) Copyright 2008 Eric Jarrige <eric.jarrige@armadeus.org> + * (C) Copyright 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> + * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.beisert@pengutronix.de> + * + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This file is based on mpc4200fec.h + * (C) Copyright Motorola, Inc., 2000 + * + * 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 __FEC_MXC_H +#define __FEC_MXC_H + +/** + * Layout description of the FEC + */ +struct ethernet_regs { + +/* [10:2]addr = 00 */ + +/* Control and status Registers (offset 000-1FF) */ + + uint32_t res0[1]; /* MBAR_ETH + 0x000 */ + uint32_t ievent; /* MBAR_ETH + 0x004 */ + uint32_t imask; /* MBAR_ETH + 0x008 */ + + uint32_t res1[1]; /* MBAR_ETH + 0x00C */ + uint32_t r_des_active; /* MBAR_ETH + 0x010 */ + uint32_t x_des_active; /* MBAR_ETH + 0x014 */ + uint32_t res2[3]; /* MBAR_ETH + 0x018-20 */ + uint32_t ecntrl; /* MBAR_ETH + 0x024 */ + + uint32_t res3[6]; /* MBAR_ETH + 0x028-03C */ + uint32_t mii_data; /* MBAR_ETH + 0x040 */ + uint32_t mii_speed; /* MBAR_ETH + 0x044 */ + uint32_t res4[7]; /* MBAR_ETH + 0x048-60 */ + uint32_t mib_control; /* MBAR_ETH + 0x064 */ + + uint32_t res5[7]; /* MBAR_ETH + 0x068-80 */ + uint32_t r_cntrl; /* MBAR_ETH + 0x084 */ + uint32_t res6[15]; /* MBAR_ETH + 0x088-C0 */ + uint32_t x_cntrl; /* MBAR_ETH + 0x0C4 */ + uint32_t res7[7]; /* MBAR_ETH + 0x0C8-E0 */ + uint32_t paddr1; /* MBAR_ETH + 0x0E4 */ + uint32_t paddr2; /* MBAR_ETH + 0x0E8 */ + uint32_t op_pause; /* MBAR_ETH + 0x0EC */ + + uint32_t res8[10]; /* MBAR_ETH + 0x0F0-114 */ + uint32_t iaddr1; /* MBAR_ETH + 0x118 */ + uint32_t iaddr2; /* MBAR_ETH + 0x11C */ + uint32_t gaddr1; /* MBAR_ETH + 0x120 */ + uint32_t gaddr2; /* MBAR_ETH + 0x124 */ + uint32_t res9[7]; /* MBAR_ETH + 0x128-140 */ + + uint32_t x_wmrk; /* MBAR_ETH + 0x144 */ + uint32_t res10[1]; /* MBAR_ETH + 0x148 */ + uint32_t r_bound; /* MBAR_ETH + 0x14C */ + uint32_t r_fstart; /* MBAR_ETH + 0x150 */ + uint32_t res11[11]; /* MBAR_ETH + 0x154-17C */ + uint32_t erdsr; /* MBAR_ETH + 0x180 */ + uint32_t etdsr; /* MBAR_ETH + 0x184 */ + uint32_t emrbr; /* MBAR_ETH + 0x188 */ + uint32_t res12[29]; /* MBAR_ETH + 0x18C-1FC */ + +/* MIB COUNTERS (Offset 200-2FF) */ + + uint32_t rmon_t_drop; /* MBAR_ETH + 0x200 */ + uint32_t rmon_t_packets; /* MBAR_ETH + 0x204 */ + uint32_t rmon_t_bc_pkt; /* MBAR_ETH + 0x208 */ + uint32_t rmon_t_mc_pkt; /* MBAR_ETH + 0x20C */ + uint32_t rmon_t_crc_align; /* MBAR_ETH + 0x210 */ + uint32_t rmon_t_undersize; /* MBAR_ETH + 0x214 */ + uint32_t rmon_t_oversize; /* MBAR_ETH + 0x218 */ + uint32_t rmon_t_frag; /* MBAR_ETH + 0x21C */ + uint32_t rmon_t_jab; /* MBAR_ETH + 0x220 */ + uint32_t rmon_t_col; /* MBAR_ETH + 0x224 */ + uint32_t rmon_t_p64; /* MBAR_ETH + 0x228 */ + uint32_t rmon_t_p65to127; /* MBAR_ETH + 0x22C */ + uint32_t rmon_t_p128to255; /* MBAR_ETH + 0x230 */ + uint32_t rmon_t_p256to511; /* MBAR_ETH + 0x234 */ + uint32_t rmon_t_p512to1023; /* MBAR_ETH + 0x238 */ + uint32_t rmon_t_p1024to2047; /* MBAR_ETH + 0x23C */ + uint32_t rmon_t_p_gte2048; /* MBAR_ETH + 0x240 */ + uint32_t rmon_t_octets; /* MBAR_ETH + 0x244 */ + uint32_t ieee_t_drop; /* MBAR_ETH + 0x248 */ + uint32_t ieee_t_frame_ok; /* MBAR_ETH + 0x24C */ + uint32_t ieee_t_1col; /* MBAR_ETH + 0x250 */ + uint32_t ieee_t_mcol; /* MBAR_ETH + 0x254 */ + uint32_t ieee_t_def; /* MBAR_ETH + 0x258 */ + uint32_t ieee_t_lcol; /* MBAR_ETH + 0x25C */ + uint32_t ieee_t_excol; /* MBAR_ETH + 0x260 */ + uint32_t ieee_t_macerr; /* MBAR_ETH + 0x264 */ + uint32_t ieee_t_cserr; /* MBAR_ETH + 0x268 */ + uint32_t ieee_t_sqe; /* MBAR_ETH + 0x26C */ + uint32_t t_fdxfc; /* MBAR_ETH + 0x270 */ + uint32_t ieee_t_octets_ok; /* MBAR_ETH + 0x274 */ + + uint32_t res13[2]; /* MBAR_ETH + 0x278-27C */ + uint32_t rmon_r_drop; /* MBAR_ETH + 0x280 */ + uint32_t rmon_r_packets; /* MBAR_ETH + 0x284 */ + uint32_t rmon_r_bc_pkt; /* MBAR_ETH + 0x288 */ + uint32_t rmon_r_mc_pkt; /* MBAR_ETH + 0x28C */ + uint32_t rmon_r_crc_align; /* MBAR_ETH + 0x290 */ + uint32_t rmon_r_undersize; /* MBAR_ETH + 0x294 */ + uint32_t rmon_r_oversize; /* MBAR_ETH + 0x298 */ + uint32_t rmon_r_frag; /* MBAR_ETH + 0x29C */ + uint32_t rmon_r_jab; /* MBAR_ETH + 0x2A0 */ + + uint32_t rmon_r_resvd_0; /* MBAR_ETH + 0x2A4 */ + + uint32_t rmon_r_p64; /* MBAR_ETH + 0x2A8 */ + uint32_t rmon_r_p65to127; /* MBAR_ETH + 0x2AC */ + uint32_t rmon_r_p128to255; /* MBAR_ETH + 0x2B0 */ + uint32_t rmon_r_p256to511; /* MBAR_ETH + 0x2B4 */ + uint32_t rmon_r_p512to1023; /* MBAR_ETH + 0x2B8 */ + uint32_t rmon_r_p1024to2047; /* MBAR_ETH + 0x2BC */ + uint32_t rmon_r_p_gte2048; /* MBAR_ETH + 0x2C0 */ + uint32_t rmon_r_octets; /* MBAR_ETH + 0x2C4 */ + uint32_t ieee_r_drop; /* MBAR_ETH + 0x2C8 */ + uint32_t ieee_r_frame_ok; /* MBAR_ETH + 0x2CC */ + uint32_t ieee_r_crc; /* MBAR_ETH + 0x2D0 */ + uint32_t ieee_r_align; /* MBAR_ETH + 0x2D4 */ + uint32_t r_macerr; /* MBAR_ETH + 0x2D8 */ + uint32_t r_fdxfc; /* MBAR_ETH + 0x2DC */ + uint32_t ieee_r_octets_ok; /* MBAR_ETH + 0x2E0 */ + + uint32_t res14[6]; /* MBAR_ETH + 0x2E4-2FC */ + + uint32_t res15[64]; /* MBAR_ETH + 0x300-3FF */ +}; + +#define FEC_IEVENT_HBERR 0x80000000 +#define FEC_IEVENT_BABR 0x40000000 +#define FEC_IEVENT_BABT 0x20000000 +#define FEC_IEVENT_GRA 0x10000000 +#define FEC_IEVENT_TXF 0x08000000 +#define FEC_IEVENT_TXB 0x04000000 +#define FEC_IEVENT_RXF 0x02000000 +#define FEC_IEVENT_RXB 0x01000000 +#define FEC_IEVENT_MII 0x00800000 +#define FEC_IEVENT_EBERR 0x00400000 +#define FEC_IEVENT_LC 0x00200000 +#define FEC_IEVENT_RL 0x00100000 +#define FEC_IEVENT_UN 0x00080000 + +#define FEC_IMASK_HBERR 0x80000000 +#define FEC_IMASK_BABR 0x40000000 +#define FEC_IMASKT_BABT 0x20000000 +#define FEC_IMASK_GRA 0x10000000 +#define FEC_IMASKT_TXF 0x08000000 +#define FEC_IMASK_TXB 0x04000000 +#define FEC_IMASKT_RXF 0x02000000 +#define FEC_IMASK_RXB 0x01000000 +#define FEC_IMASK_MII 0x00800000 +#define FEC_IMASK_EBERR 0x00400000 +#define FEC_IMASK_LC 0x00200000 +#define FEC_IMASKT_RL 0x00100000 +#define FEC_IMASK_UN 0x00080000 + + +#define FEC_RCNTRL_MAX_FL_SHIFT 16 +#define FEC_RCNTRL_LOOP 0x00000001 +#define FEC_RCNTRL_DRT 0x00000002 +#define FEC_RCNTRL_MII_MODE 0x00000004 +#define FEC_RCNTRL_PROM 0x00000008 +#define FEC_RCNTRL_BC_REJ 0x00000010 +#define FEC_RCNTRL_FCE 0x00000020 + +#define FEC_TCNTRL_GTS 0x00000001 +#define FEC_TCNTRL_HBC 0x00000002 +#define FEC_TCNTRL_FDEN 0x00000004 +#define FEC_TCNTRL_TFC_PAUSE 0x00000008 +#define FEC_TCNTRL_RFC_PAUSE 0x00000010 + +#define FEC_ECNTRL_RESET 0x00000001 /* reset the FEC */ +#define FEC_ECNTRL_ETHER_EN 0x00000002 /* enable the FEC */ + +/** + * @brief Descriptor buffer alignment + * + * i.MX27 requires a 16 byte alignment (but for the first element only) + */ +#define DB_ALIGNMENT 16 + +/** + * @brief Data buffer alignment + * + * i.MX27 requires a four byte alignment for transmit and 16 bits + * alignment for receive so take 16 + * Note: Valid for member data_pointer in struct buffer_descriptor + */ +#define DB_DATA_ALIGNMENT 16 + +/** + * @brief Receive & Transmit Buffer Descriptor definitions + * + * Note: The first BD must be aligned (see DB_ALIGNMENT) + */ +struct fec_bd { + uint16_t data_length; /* payload's length in bytes */ + uint16_t status; /* BD's staus (see datasheet) */ + uint32_t data_pointer; /* payload's buffer address */ +}; + +/** + * Supported phy types on this platform + */ +enum xceiver_type { + SEVENWIRE, /* 7-wire */ + MII10, /* MII 10Mbps */ + MII100 /* MII 100Mbps */ +}; + +/** + * @brief i.MX27-FEC private structure + */ +struct fec_priv { + struct ethernet_regs *eth; /* pointer to register'S base */ + enum xceiver_type xcv_type; /* transceiver type */ + struct fec_bd *rbd_base; /* RBD ring */ + int rbd_index; /* next receive BD to read */ + struct fec_bd *tbd_base; /* TBD ring */ + int tbd_index; /* next transmit BD to write */ + bd_t *bd; + void *rdb_ptr; + void *base_ptr; +}; + +/** + * @brief Numbers of buffer descriptors for receiving + * + * The number defines the stocked memory buffers for the receiving task. + * Larger values makes no sense in this limited environment. + */ +#define FEC_RBD_NUM 64 + +/** + * @brief Define the ethernet packet size limit in memory + * + * Note: Do not shrink this number. This will force the FEC to spread larger + * frames in more than one BD. This is nothing to worry about, but the current + * driver can't handle it. + */ +#define FEC_MAX_PKT_SIZE 1536 + +/* Receive BD status bits */ +#define FEC_RBD_EMPTY 0x8000 /* Receive BD status: Buffer is empty */ +#define FEC_RBD_WRAP 0x2000 /* Receive BD status: Last BD in ring */ +/* Receive BD status: Buffer is last in frame (useless here!) */ +#define FEC_RBD_LAST 0x0800 +#define FEC_RBD_MISS 0x0100 /* Receive BD status: Miss bit for prom mode */ +/* Receive BD status: The received frame is broadcast frame */ +#define FEC_RBD_BC 0x0080 +/* Receive BD status: The received frame is multicast frame */ +#define FEC_RBD_MC 0x0040 +#define FEC_RBD_LG 0x0020 /* Receive BD status: Frame length violation */ +#define FEC_RBD_NO 0x0010 /* Receive BD status: Nonoctet align frame */ +#define FEC_RBD_CR 0x0004 /* Receive BD status: CRC error */ +#define FEC_RBD_OV 0x0002 /* Receive BD status: Receive FIFO overrun */ +#define FEC_RBD_TR 0x0001 /* Receive BD status: Frame is truncated */ +#define FEC_RBD_ERR (FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \ + FEC_RBD_OV | FEC_RBD_TR) + +/* Transmit BD status bits */ +#define FEC_TBD_READY 0x8000 /* Tansmit BD status: Buffer is ready */ +#define FEC_TBD_WRAP 0x2000 /* Tansmit BD status: Mark as last BD in ring */ +#define FEC_TBD_LAST 0x0800 /* Tansmit BD status: Buffer is last in frame */ +#define FEC_TBD_TC 0x0400 /* Tansmit BD status: Transmit the CRC */ +#define FEC_TBD_ABC 0x0200 /* Tansmit BD status: Append bad CRC */ + +/* MII-related definitios */ +#define FEC_MII_DATA_ST 0x40000000 /* Start of frame delimiter */ +#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform a read operation */ +#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform a write operation */ +#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address field mask */ +#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register field mask */ +#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */ +#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data field */ + +#define FEC_MII_DATA_RA_SHIFT 18 /* MII Register address bits */ +#define FEC_MII_DATA_PA_SHIFT 23 /* MII PHY address bits */ + +#endif /* __FEC_MXC_H */ diff --git a/drivers/net/kirkwood_egiga.c b/drivers/net/kirkwood_egiga.c index 3c5db19..701812b 100644 --- a/drivers/net/kirkwood_egiga.c +++ b/drivers/net/kirkwood_egiga.c @@ -49,7 +49,7 @@ static int smi_reg_read(char *devname, u8 phy_adr, u8 reg_ofs, u16 * data) struct kwgbe_device *dkwgbe = to_dkwgbe(dev); struct kwgbe_registers *regs = dkwgbe->regs; u32 smi_reg; - volatile u32 timeout; + u32 timeout; /* Phyadr read request */ if (phy_adr == 0xEE && reg_ofs == 0xEE) { @@ -124,7 +124,7 @@ static int smi_reg_write(char *devname, u8 phy_adr, u8 reg_ofs, u16 data) struct kwgbe_device *dkwgbe = to_dkwgbe(dev); struct kwgbe_registers *regs = dkwgbe->regs; u32 smi_reg; - volatile u32 timeout; + u32 timeout; /* Phyadr write request*/ if (phy_adr == 0xEE && reg_ofs == 0xEE) { @@ -370,7 +370,7 @@ static void port_uc_addr_set(struct kwgbe_registers *regs, u8 * p_addr) */ static void kwgbe_init_rx_desc_ring(struct kwgbe_device *dkwgbe) { - volatile struct kwgbe_rxdesc *p_rx_desc; + struct kwgbe_rxdesc *p_rx_desc; int i; /* initialize the Rx descriptors ring */ @@ -487,6 +487,7 @@ static int kwgbe_send(struct eth_device *dev, volatile void *dataptr, struct kwgbe_device *dkwgbe = to_dkwgbe(dev); struct kwgbe_registers *regs = dkwgbe->regs; struct kwgbe_txdesc *p_txdesc = dkwgbe->p_txdesc; + u32 cmd_sts; if ((u32) dataptr & 0x07) { printf("Err..(%s) xmit dataptr not 64bit aligned\n", @@ -507,21 +508,26 @@ static int kwgbe_send(struct eth_device *dev, volatile void *dataptr, /* * wait for packet xmit completion */ - while (p_txdesc->cmd_sts & KWGBE_BUFFER_OWNED_BY_DMA) { + cmd_sts = readl(&p_txdesc->cmd_sts); + while (cmd_sts & KWGBE_BUFFER_OWNED_BY_DMA) { /* return fail if error is detected */ - if (p_txdesc->cmd_sts & (KWGBE_UR_ERROR | KWGBE_RL_ERROR)) { + if ((cmd_sts & (KWGBE_ERROR_SUMMARY | KWGBE_TX_LAST_FRAME)) == + (KWGBE_ERROR_SUMMARY | KWGBE_TX_LAST_FRAME) && + cmd_sts & (KWGBE_UR_ERROR | KWGBE_RL_ERROR)) { printf("Err..(%s) in xmit packet\n", __FUNCTION__); return -1; } + cmd_sts = readl(&p_txdesc->cmd_sts); }; return 0; } static int kwgbe_recv(struct eth_device *dev) { - volatile struct kwgbe_device *dkwgbe = to_dkwgbe(dev); - volatile struct kwgbe_rxdesc *p_rxdesc_curr = dkwgbe->p_rxdesc_curr; - volatile u32 timeout = 0; + struct kwgbe_device *dkwgbe = to_dkwgbe(dev); + struct kwgbe_rxdesc *p_rxdesc_curr = dkwgbe->p_rxdesc_curr; + u32 cmd_sts; + u32 timeout = 0; /* wait untill rx packet available or timeout */ do { @@ -531,7 +537,7 @@ static int kwgbe_recv(struct eth_device *dev) debug("%s time out...\n", __FUNCTION__); return -1; } - } while (p_rxdesc_curr->cmd_sts & KWGBE_BUFFER_OWNED_BY_DMA); + } while (readl(&p_rxdesc_curr->cmd_sts) & KWGBE_BUFFER_OWNED_BY_DMA); if (p_rxdesc_curr->byte_cnt != 0) { debug("%s: Received %d byte Packet @ 0x%x (cmd_sts= %08x)\n", @@ -545,14 +551,16 @@ static int kwgbe_recv(struct eth_device *dev) * OR the error summary bit is on, * the packets needs to be dropeed. */ - if ((p_rxdesc_curr->cmd_sts & + cmd_sts = readl(&p_rxdesc_curr->cmd_sts); + + if ((cmd_sts & (KWGBE_RX_FIRST_DESC | KWGBE_RX_LAST_DESC)) != (KWGBE_RX_FIRST_DESC | KWGBE_RX_LAST_DESC)) { printf("Err..(%s) Dropping packet spread on" " multiple descriptors\n", __FUNCTION__); - } else if (p_rxdesc_curr->cmd_sts & KWGBE_ERROR_SUMMARY) { + } else if (cmd_sts & KWGBE_ERROR_SUMMARY) { printf("Err..(%s) Dropping packet with errors\n", __FUNCTION__); @@ -574,7 +582,8 @@ static int kwgbe_recv(struct eth_device *dev) p_rxdesc_curr->buf_size = PKTSIZE_ALIGN; p_rxdesc_curr->byte_cnt = 0; - dkwgbe->p_rxdesc_curr = p_rxdesc_curr->nxtdesc_p; + writel((unsigned)p_rxdesc_curr->nxtdesc_p, &dkwgbe->p_rxdesc_curr); + return 0; } diff --git a/drivers/net/kirkwood_egiga.h b/drivers/net/kirkwood_egiga.h index 8b67c9c..9c893d1 100644 --- a/drivers/net/kirkwood_egiga.h +++ b/drivers/net/kirkwood_egiga.h @@ -256,6 +256,7 @@ #define KWGBE_UR_ERROR (1 << 1) #define KWGBE_RL_ERROR (1 << 2) #define KWGBE_LLC_SNAP_FORMAT (1 << 9) +#define KWGBE_TX_LAST_FRAME (1 << 20) /* Rx descriptors status */ #define KWGBE_CRC_ERROR 0 diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index b2ee5ea..f5329a5 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -23,7 +23,7 @@ #include <common.h> #include <command.h> -#include <devices.h> +#include <stdio_dev.h> #include <net.h> DECLARE_GLOBAL_DATA_PTR; @@ -243,7 +243,7 @@ int nc_tstc (void) int drv_nc_init (void) { - device_t dev; + struct stdio_dev dev; int rc; memset (&dev, 0, sizeof (dev)); @@ -256,7 +256,7 @@ int drv_nc_init (void) dev.getc = nc_getc; dev.tstc = nc_tstc; - rc = device_register (&dev); + rc = stdio_register (&dev); return (rc == 0) ? 1 : rc; } diff --git a/drivers/net/phy/miiphybb.c b/drivers/net/phy/miiphybb.c index e3c163a..b77c917 100644 --- a/drivers/net/phy/miiphybb.c +++ b/drivers/net/phy/miiphybb.c @@ -127,6 +127,11 @@ int bb_miiphy_read (char *devname, unsigned char addr, volatile ioport_t *iop = ioport_addr ((immap_t *) CONFIG_SYS_IMMR, MDIO_PORT); #endif + if (value == NULL) { + puts("NULL value pointer\n"); + return (-1); + } + miiphy_pre (1, addr, reg); /* tri-state our MDIO I/O pin so we can read */ @@ -145,6 +150,8 @@ int bb_miiphy_read (char *devname, unsigned char addr, MDC (1); MIIDELAY; } + /* There is no PHY, set value to 0xFFFF and return */ + *value = 0xFFFF; return (-1); } diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c index ec47286..29630f5 100644 --- a/drivers/net/phy/mv88e61xx.c +++ b/drivers/net/phy/mv88e61xx.c @@ -36,7 +36,7 @@ * By default single chip mode is configured * multichip mode operation can be configured in board header */ -static int mv88e61xx_busychk_multic(u32 devaddr) +static int mv88e61xx_busychk_multic(char *name, u32 devaddr) { u32 reg = 0; u32 timeout = MV88E61XX_PHY_TIMEOUT; @@ -58,11 +58,11 @@ static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data) u32 mii_dev_addr; /* command to read PHY dev address */ - if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) { + if (miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) { printf("Error..could not read PHY dev address\n"); return; } - mv88e61xx_busychk_multic(mii_dev_addr); + mv88e61xx_busychk_multic(name, mii_dev_addr); /* Write data to Switch indirect data register */ miiphy_write(name, mii_dev_addr, 0x1, data); /* Write command to Switch indirect command register (write) */ @@ -77,18 +77,18 @@ static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data) u32 mii_dev_addr; /* command to read PHY dev address */ - if (!miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) { + if (miiphy_read(name, 0xEE, 0xEE, &mii_dev_addr)) { printf("Error..could not read PHY dev address\n"); return; } - mv88e61xx_busychk_multic(mii_dev_addr); + mv88e61xx_busychk_multic(name, mii_dev_addr); /* Write command to Switch indirect command register (read) */ miiphy_write(name, mii_dev_addr, 0x0, - reg_ofs | (phy_adr << 5) | (1 << 10) | (1 << 12) | (1 << + reg_ofs | (phy_adr << 5) | (1 << 11) | (1 << 12) | (1 << 15)); - mv88e61xx_busychk_multic(mii_dev_addr); + mv88e61xx_busychk_multic(name, mii_dev_addr); /* Read data from Switch indirect data register */ - miiphy_read(name, mii_dev_addr, 0x1, (u16 *) & data); + miiphy_read(name, mii_dev_addr, 0x1, data); } #endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */ @@ -212,7 +212,7 @@ static int mv88e61xx_busychk(char *name) printf("SMI busy timeout\n"); return -1; } - } while (reg & 1 << 28); /* busy mask */ + } while (reg & 1 << 15); /* busy mask */ return 0; } diff --git a/drivers/net/phy/mv88e61xx.h b/drivers/net/phy/mv88e61xx.h index 4279464..57762b6 100644 --- a/drivers/net/phy/mv88e61xx.h +++ b/drivers/net/phy/mv88e61xx.h @@ -49,7 +49,7 @@ #define MV88E61XX_ADDR_OFST 5 #ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE -static int mv88e61xx_busychk_multic(u32 devaddr); +static int mv88e61xx_busychk_multic(char *name, u32 devaddr); static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data); static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data); #define WR_PHY mv88e61xx_wr_phy diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index f24ded2..86cc324 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -546,7 +546,7 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) /* Configure phy */ ret = sh_eth_phy_config(eth); if (ret) { - printf(SHETHER_NAME ":i phy config timeout\n"); + printf(SHETHER_NAME ": phy config timeout\n"); goto err_phy_cfg; } /* Read phy status to finish configuring the e-mac */ diff --git a/drivers/net/sk98lin/Makefile b/drivers/net/sk98lin/Makefile index f1bc4a7..4a3ead3 100644 --- a/drivers/net/sk98lin/Makefile +++ b/drivers/net/sk98lin/Makefile @@ -90,7 +90,7 @@ endif EXTRA_CFLAGS += -I. -DSK_USE_CSUM $(DBGDEF) CFLAGS += $(EXTRA_CFLAGS) -HOST_CFLAGS += $(EXTRA_CFLAGS) +HOSTCFLAGS += $(EXTRA_CFLAGS) all: $(LIB) diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 8c9a2a8..18a729c 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -24,110 +24,90 @@ #include <common.h> #include <command.h> +#include <malloc.h> #include <net.h> #include <miiphy.h> #include "smc911x.h" -u32 pkt_data_pull(u32 addr) \ +u32 pkt_data_pull(struct eth_device *dev, u32 addr) \ __attribute__ ((weak, alias ("smc911x_reg_read"))); -void pkt_data_push(u32 addr, u32 val) \ +void pkt_data_push(struct eth_device *dev, u32 addr, u32 val) \ __attribute__ ((weak, alias ("smc911x_reg_write"))); #define mdelay(n) udelay((n)*1000) -static int smx911x_handle_mac_address(bd_t *bd) +static void smx911x_handle_mac_address(struct eth_device *dev) { unsigned long addrh, addrl; - uchar m[6]; - - if (eth_getenv_enetaddr("ethaddr", m)) { - /* if the environment has a valid mac address then use it */ - addrl = m[0] | (m[1] << 8) | (m[2] << 16) | (m[3] << 24); - addrh = m[4] | (m[5] << 8); - smc911x_set_mac_csr(ADDRL, addrl); - smc911x_set_mac_csr(ADDRH, addrh); - } else { - /* if not, try to get one from the eeprom */ - addrh = smc911x_get_mac_csr(ADDRH); - addrl = smc911x_get_mac_csr(ADDRL); - - m[0] = (addrl ) & 0xff; - m[1] = (addrl >> 8 ) & 0xff; - m[2] = (addrl >> 16 ) & 0xff; - m[3] = (addrl >> 24 ) & 0xff; - m[4] = (addrh ) & 0xff; - m[5] = (addrh >> 8 ) & 0xff; - - /* we get 0xff when there is no eeprom connected */ - if ((m[0] & m[1] & m[2] & m[3] & m[4] & m[5]) == 0xff) { - printf(DRIVERNAME ": no valid mac address in environment " - "and no eeprom found\n"); - return -1; - } - - eth_setenv_enetaddr("ethaddr", m); - } + uchar *m = dev->enetaddr; - printf(DRIVERNAME ": MAC %pM\n", m); + addrl = m[0] | (m[1] << 8) | (m[2] << 16) | (m[3] << 24); + addrh = m[4] | (m[5] << 8); + smc911x_set_mac_csr(dev, ADDRL, addrl); + smc911x_set_mac_csr(dev, ADDRH, addrh); - return 0; + printf(DRIVERNAME ": MAC %pM\n", m); } -static int smc911x_miiphy_read(u8 phy, u8 reg, u16 *val) +static int smc911x_miiphy_read(struct eth_device *dev, + u8 phy, u8 reg, u16 *val) { - while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) + while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY) ; - smc911x_set_mac_csr(MII_ACC, phy << 11 | reg << 6 | MII_ACC_MII_BUSY); + smc911x_set_mac_csr(dev, MII_ACC, phy << 11 | reg << 6 | + MII_ACC_MII_BUSY); - while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) + while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY) ; - *val = smc911x_get_mac_csr(MII_DATA); + *val = smc911x_get_mac_csr(dev, MII_DATA); return 0; } -static int smc911x_miiphy_write(u8 phy, u8 reg, u16 val) +static int smc911x_miiphy_write(struct eth_device *dev, + u8 phy, u8 reg, u16 val) { - while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) + while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY) ; - smc911x_set_mac_csr(MII_DATA, val); - smc911x_set_mac_csr(MII_ACC, + smc911x_set_mac_csr(dev, MII_DATA, val); + smc911x_set_mac_csr(dev, MII_ACC, phy << 11 | reg << 6 | MII_ACC_MII_BUSY | MII_ACC_MII_WRITE); - while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) + while (smc911x_get_mac_csr(dev, MII_ACC) & MII_ACC_MII_BUSY) ; return 0; } -static int smc911x_phy_reset(void) +static int smc911x_phy_reset(struct eth_device *dev) { u32 reg; - reg = smc911x_reg_read(PMT_CTRL); + reg = smc911x_reg_read(dev, PMT_CTRL); reg &= ~0xfffff030; reg |= PMT_CTRL_PHY_RST; - smc911x_reg_write(PMT_CTRL, reg); + smc911x_reg_write(dev, PMT_CTRL, reg); mdelay(100); return 0; } -static void smc911x_phy_configure(void) +static void smc911x_phy_configure(struct eth_device *dev) { int timeout; u16 status; - smc911x_phy_reset(); + smc911x_phy_reset(dev); - smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_RESET); + smc911x_miiphy_write(dev, 1, PHY_BMCR, PHY_BMCR_RESET); mdelay(1); - smc911x_miiphy_write(1, PHY_ANAR, 0x01e1); - smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); + smc911x_miiphy_write(dev, 1, PHY_ANAR, 0x01e1); + smc911x_miiphy_write(dev, 1, PHY_BMCR, PHY_BMCR_AUTON | + PHY_BMCR_RST_NEG); timeout = 5000; do { @@ -135,7 +115,7 @@ static void smc911x_phy_configure(void) if ((timeout--) == 0) goto err_out; - if (smc911x_miiphy_read(1, PHY_BMSR, &status) != 0) + if (smc911x_miiphy_read(dev, 1, PHY_BMSR, &status) != 0) goto err_out; } while (!(status & PHY_BMSR_LS)); @@ -147,39 +127,39 @@ err_out: printf(DRIVERNAME ": autonegotiation timed out\n"); } -static void smc911x_enable(void) +static void smc911x_enable(struct eth_device *dev) { /* Enable TX */ - smc911x_reg_write(HW_CFG, 8 << 16 | HW_CFG_SF); + smc911x_reg_write(dev, HW_CFG, 8 << 16 | HW_CFG_SF); - smc911x_reg_write(GPT_CFG, GPT_CFG_TIMER_EN | 10000); + smc911x_reg_write(dev, GPT_CFG, GPT_CFG_TIMER_EN | 10000); - smc911x_reg_write(TX_CFG, TX_CFG_TX_ON); + smc911x_reg_write(dev, TX_CFG, TX_CFG_TX_ON); /* no padding to start of packets */ - smc911x_reg_write(RX_CFG, 0); + smc911x_reg_write(dev, RX_CFG, 0); - smc911x_set_mac_csr(MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN | MAC_CR_HBDIS); + smc911x_set_mac_csr(dev, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN | + MAC_CR_HBDIS); } -int eth_init(bd_t *bd) +static int smc911x_init(struct eth_device *dev, bd_t * bd) { printf(DRIVERNAME ": initializing\n"); - if (smc911x_detect_chip()) + if (smc911x_detect_chip(dev)) goto err_out; - smc911x_reset(); + smc911x_reset(dev); /* Configure the PHY, initialize the link state */ - smc911x_phy_configure(); + smc911x_phy_configure(dev); - if (smx911x_handle_mac_address(bd)) - goto err_out; + smx911x_handle_mac_address(dev); /* Turn on Tx + Rx */ - smc911x_enable(); + smc911x_enable(dev); return 0; @@ -187,28 +167,32 @@ err_out: return -1; } -int eth_send(volatile void *packet, int length) +static int smc911x_send(struct eth_device *dev, + volatile void *packet, int length) { u32 *data = (u32*)packet; u32 tmplen; u32 status; - smc911x_reg_write(TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG | TX_CMD_A_INT_LAST_SEG | length); - smc911x_reg_write(TX_DATA_FIFO, length); + smc911x_reg_write(dev, TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG | + TX_CMD_A_INT_LAST_SEG | length); + smc911x_reg_write(dev, TX_DATA_FIFO, length); tmplen = (length + 3) / 4; while (tmplen--) - pkt_data_push(TX_DATA_FIFO, *data++); + pkt_data_push(dev, TX_DATA_FIFO, *data++); /* wait for transmission */ - while (!((smc911x_reg_read(TX_FIFO_INF) & TX_FIFO_INF_TSUSED) >> 16)); + while (!((smc911x_reg_read(dev, TX_FIFO_INF) & + TX_FIFO_INF_TSUSED) >> 16)); /* get status. Ignore 'no carrier' error, it has no meaning for * full duplex operation */ - status = smc911x_reg_read(TX_STATUS_FIFO) & (TX_STS_LOC | TX_STS_LATE_COLL | - TX_STS_MANY_COLL | TX_STS_MANY_DEFER | TX_STS_UNDERRUN); + status = smc911x_reg_read(dev, TX_STATUS_FIFO) & + (TX_STS_LOC | TX_STS_LATE_COLL | TX_STS_MANY_COLL | + TX_STS_MANY_DEFER | TX_STS_UNDERRUN); if (!status) return 0; @@ -223,26 +207,26 @@ int eth_send(volatile void *packet, int length) return -1; } -void eth_halt(void) +static void smc911x_halt(struct eth_device *dev) { - smc911x_reset(); + smc911x_reset(dev); } -int eth_rx(void) +static int smc911x_rx(struct eth_device *dev) { u32 *data = (u32 *)NetRxPackets[0]; u32 pktlen, tmplen; u32 status; - if ((smc911x_reg_read(RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) { - status = smc911x_reg_read(RX_STATUS_FIFO); + if ((smc911x_reg_read(dev, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) { + status = smc911x_reg_read(dev, RX_STATUS_FIFO); pktlen = (status & RX_STS_PKT_LEN) >> 16; - smc911x_reg_write(RX_CFG, 0); + smc911x_reg_write(dev, RX_CFG, 0); tmplen = (pktlen + 2+ 3) / 4; while (tmplen--) - *data++ = pkt_data_pull(RX_DATA_FIFO); + *data++ = pkt_data_pull(dev, RX_DATA_FIFO); if (status & RX_STS_ES) printf(DRIVERNAME @@ -254,3 +238,36 @@ int eth_rx(void) return 0; } + +int smc911x_initialize(u8 dev_num, int base_addr) +{ + unsigned long addrl, addrh; + struct eth_device *dev; + + dev = malloc(sizeof(*dev)); + if (!dev) { + free(dev); + return 0; + } + memset(dev, 0, sizeof(*dev)); + + dev->iobase = base_addr; + + addrh = smc911x_get_mac_csr(dev, ADDRH); + addrl = smc911x_get_mac_csr(dev, ADDRL); + dev->enetaddr[0] = addrl; + dev->enetaddr[1] = addrl >> 8; + dev->enetaddr[2] = addrl >> 16; + dev->enetaddr[3] = addrl >> 24; + dev->enetaddr[4] = addrh; + dev->enetaddr[5] = addrh >> 8; + + dev->init = smc911x_init; + dev->halt = smc911x_halt; + dev->send = smc911x_send; + dev->recv = smc911x_rx; + sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num); + + eth_register(dev); + return 0; +} diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h index 80d2ce0..053e330 100644 --- a/drivers/net/smc911x.h +++ b/drivers/net/smc911x.h @@ -27,45 +27,51 @@ #include <linux/types.h> -#if defined (CONFIG_DRIVER_SMC911X_32_BIT) && \ - defined (CONFIG_DRIVER_SMC911X_16_BIT) -#error "SMC911X: Only one of CONFIG_DRIVER_SMC911X_32_BIT and \ - CONFIG_DRIVER_SMC911X_16_BIT shall be set" +#define DRIVERNAME "smc911x" + +#if defined (CONFIG_SMC911X_32_BIT) && \ + defined (CONFIG_SMC911X_16_BIT) +#error "SMC911X: Only one of CONFIG_SMC911X_32_BIT and \ + CONFIG_SMC911X_16_BIT shall be set" #endif -#if defined (CONFIG_DRIVER_SMC911X_32_BIT) -static inline u32 __smc911x_reg_read(u32 addr) +#if defined (CONFIG_SMC911X_32_BIT) +static inline u32 __smc911x_reg_read(struct eth_device *dev, u32 offset) { - return *(volatile u32*)addr; + return *(volatile u32*)(dev->iobase + offset); } -u32 smc911x_reg_read(u32 addr) __attribute__((weak, alias("__smc911x_reg_read"))); +u32 smc911x_reg_read(struct eth_device *dev, u32 offset) + __attribute__((weak, alias("__smc911x_reg_read"))); -static inline void __smc911x_reg_write(u32 addr, u32 val) +static inline void __smc911x_reg_write(struct eth_device *dev, + u32 offset, u32 val) { - *(volatile u32*)addr = val; + *(volatile u32*)(dev->iobase + offset) = val; } -void smc911x_reg_write(u32 addr, u32 val) __attribute__((weak, alias("__smc911x_reg_write"))); -#elif defined (CONFIG_DRIVER_SMC911X_16_BIT) -static inline u32 smc911x_reg_read(u32 addr) +void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val) + __attribute__((weak, alias("__smc911x_reg_write"))); +#elif defined (CONFIG_SMC911X_16_BIT) +static inline u32 smc911x_reg_read(struct eth_device *dev, u32 offset) { - volatile u16 *addr_16 = (u16 *)addr; + volatile u16 *addr_16 = (u16 *)(dev->iobase + offset); return ((*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16)); } -static inline void smc911x_reg_write(u32 addr, u32 val) +static inline void smc911x_reg_write(struct eth_device *dev, + u32 offset, u32 val) { - *(volatile u16*)addr = (u16)val; - *(volatile u16*)(addr + 2) = (u16)(val >> 16); + *(volatile u16 *)(dev->iobase + offset) = (u16)val; + *(volatile u16 *)(dev->iobase + offset + 2) = (u16)(val >> 16); } #else #error "SMC911X: undefined bus width" -#endif /* CONFIG_DRIVER_SMC911X_16_BIT */ +#endif /* CONFIG_SMC911X_16_BIT */ /* Below are the register offsets and bit definitions * of the Lan911x memory space */ -#define RX_DATA_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x00) +#define RX_DATA_FIFO 0x00 -#define TX_DATA_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x20) +#define TX_DATA_FIFO 0x20 #define TX_CMD_A_INT_ON_COMP 0x80000000 #define TX_CMD_A_INT_BUF_END_ALGN 0x03000000 #define TX_CMD_A_INT_4_BYTE_ALGN 0x00000000 @@ -80,7 +86,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val) #define TX_CMD_B_DISABLE_PADDING 0x00001000 #define TX_CMD_B_PKT_BYTE_LENGTH 0x000007FF -#define RX_STATUS_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x40) +#define RX_STATUS_FIFO 0x40 #define RX_STS_PKT_LEN 0x3FFF0000 #define RX_STS_ES 0x00008000 #define RX_STS_BCST 0x00002000 @@ -94,8 +100,8 @@ static inline void smc911x_reg_write(u32 addr, u32 val) #define RX_STS_MII_ERR 0x00000008 #define RX_STS_DRIBBLING 0x00000004 #define RX_STS_CRC_ERR 0x00000002 -#define RX_STATUS_FIFO_PEEK (CONFIG_DRIVER_SMC911X_BASE + 0x44) -#define TX_STATUS_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x48) +#define RX_STATUS_FIFO_PEEK 0x44 +#define TX_STATUS_FIFO 0x48 #define TX_STS_TAG 0xFFFF0000 #define TX_STS_ES 0x00008000 #define TX_STS_LOC 0x00000800 @@ -106,21 +112,23 @@ static inline void smc911x_reg_write(u32 addr, u32 val) #define TX_STS_MANY_DEFER 0x00000004 #define TX_STS_UNDERRUN 0x00000002 #define TX_STS_DEFERRED 0x00000001 -#define TX_STATUS_FIFO_PEEK (CONFIG_DRIVER_SMC911X_BASE + 0x4C) -#define ID_REV (CONFIG_DRIVER_SMC911X_BASE + 0x50) +#define TX_STATUS_FIFO_PEEK 0x4C +#define ID_REV 0x50 #define ID_REV_CHIP_ID 0xFFFF0000 /* RO */ #define ID_REV_REV_ID 0x0000FFFF /* RO */ -#define INT_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x54) +#define INT_CFG 0x54 #define INT_CFG_INT_DEAS 0xFF000000 /* R/W */ #define INT_CFG_INT_DEAS_CLR 0x00004000 #define INT_CFG_INT_DEAS_STS 0x00002000 #define INT_CFG_IRQ_INT 0x00001000 /* RO */ #define INT_CFG_IRQ_EN 0x00000100 /* R/W */ -#define INT_CFG_IRQ_POL 0x00000010 /* R/W Not Affected by SW Reset */ -#define INT_CFG_IRQ_TYPE 0x00000001 /* R/W Not Affected by SW Reset */ + /* R/W Not Affected by SW Reset */ +#define INT_CFG_IRQ_POL 0x00000010 + /* R/W Not Affected by SW Reset */ +#define INT_CFG_IRQ_TYPE 0x00000001 -#define INT_STS (CONFIG_DRIVER_SMC911X_BASE + 0x58) +#define INT_STS 0x58 #define INT_STS_SW_INT 0x80000000 /* R/WC */ #define INT_STS_TXSTOP_INT 0x02000000 /* R/WC */ #define INT_STS_RXSTOP_INT 0x01000000 /* R/WC */ @@ -149,7 +157,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val) #define INT_STS_GPIO2_INT 0x00000004 /* R/WC */ #define INT_STS_GPIO1_INT 0x00000002 /* R/WC */ #define INT_STS_GPIO0_INT 0x00000001 /* R/WC */ -#define INT_EN (CONFIG_DRIVER_SMC911X_BASE + 0x5C) +#define INT_EN 0x5C #define INT_EN_SW_INT_EN 0x80000000 /* R/W */ #define INT_EN_TXSTOP_INT_EN 0x02000000 /* R/W */ #define INT_EN_RXSTOP_INT_EN 0x01000000 /* R/W */ @@ -179,14 +187,14 @@ static inline void smc911x_reg_write(u32 addr, u32 val) #define INT_EN_GPIO1_INT 0x00000002 /* R/W */ #define INT_EN_GPIO0_INT 0x00000001 /* R/W */ -#define BYTE_TEST (CONFIG_DRIVER_SMC911X_BASE + 0x64) -#define FIFO_INT (CONFIG_DRIVER_SMC911X_BASE + 0x68) +#define BYTE_TEST 0x64 +#define FIFO_INT 0x68 #define FIFO_INT_TX_AVAIL_LEVEL 0xFF000000 /* R/W */ #define FIFO_INT_TX_STS_LEVEL 0x00FF0000 /* R/W */ #define FIFO_INT_RX_AVAIL_LEVEL 0x0000FF00 /* R/W */ #define FIFO_INT_RX_STS_LEVEL 0x000000FF /* R/W */ -#define RX_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x6C) +#define RX_CFG 0x6C #define RX_CFG_RX_END_ALGN 0xC0000000 /* R/W */ #define RX_CFG_RX_END_ALGN4 0x00000000 /* R/W */ #define RX_CFG_RX_END_ALGN16 0x40000000 /* R/W */ @@ -196,16 +204,17 @@ static inline void smc911x_reg_write(u32 addr, u32 val) #define RX_CFG_RXDOFF 0x00001F00 /* R/W */ /*#define RX_CFG_RXBAD 0x00000001*/ /* R/W */ -#define TX_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x70) +#define TX_CFG 0x70 /*#define TX_CFG_TX_DMA_LVL 0xE0000000*/ /* R/W */ -/*#define TX_CFG_TX_DMA_CNT 0x0FFF0000*/ /* R/W Self Clearing */ + /* R/W Self Clearing */ +/*#define TX_CFG_TX_DMA_CNT 0x0FFF0000*/ #define TX_CFG_TXS_DUMP 0x00008000 /* Self Clearing */ #define TX_CFG_TXD_DUMP 0x00004000 /* Self Clearing */ #define TX_CFG_TXSAO 0x00000004 /* R/W */ #define TX_CFG_TX_ON 0x00000002 /* R/W */ #define TX_CFG_STOP_TX 0x00000001 /* Self Clearing */ -#define HW_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x74) +#define HW_CFG 0x74 #define HW_CFG_TTM 0x00200000 /* R/W */ #define HW_CFG_SF 0x00100000 /* R/W */ #define HW_CFG_TX_FIF_SZ 0x000F0000 /* R/W */ @@ -221,24 +230,25 @@ static inline void smc911x_reg_write(u32 addr, u32 val) #define HW_CFG_SRST_TO 0x00000002 /* RO */ #define HW_CFG_SRST 0x00000001 /* Self Clearing */ -#define RX_DP_CTRL (CONFIG_DRIVER_SMC911X_BASE + 0x78) +#define RX_DP_CTRL 0x78 #define RX_DP_CTRL_RX_FFWD 0x80000000 /* R/W */ #define RX_DP_CTRL_FFWD_BUSY 0x80000000 /* RO */ -#define RX_FIFO_INF (CONFIG_DRIVER_SMC911X_BASE + 0x7C) +#define RX_FIFO_INF 0x7C #define RX_FIFO_INF_RXSUSED 0x00FF0000 /* RO */ #define RX_FIFO_INF_RXDUSED 0x0000FFFF /* RO */ -#define TX_FIFO_INF (CONFIG_DRIVER_SMC911X_BASE + 0x80) +#define TX_FIFO_INF 0x80 #define TX_FIFO_INF_TSUSED 0x00FF0000 /* RO */ #define TX_FIFO_INF_TDFREE 0x0000FFFF /* RO */ -#define PMT_CTRL (CONFIG_DRIVER_SMC911X_BASE + 0x84) +#define PMT_CTRL 0x84 #define PMT_CTRL_PM_MODE 0x00003000 /* Self Clearing */ #define PMT_CTRL_PHY_RST 0x00000400 /* Self Clearing */ #define PMT_CTRL_WOL_EN 0x00000200 /* R/W */ #define PMT_CTRL_ED_EN 0x00000100 /* R/W */ -#define PMT_CTRL_PME_TYPE 0x00000040 /* R/W Not Affected by SW Reset */ + /* R/W Not Affected by SW Reset */ +#define PMT_CTRL_PME_TYPE 0x00000040 #define PMT_CTRL_WUPS 0x00000030 /* R/WC */ #define PMT_CTRL_WUPS_NOWAKE 0x00000000 /* R/WC */ #define PMT_CTRL_WUPS_ED 0x00000010 /* R/WC */ @@ -246,10 +256,11 @@ static inline void smc911x_reg_write(u32 addr, u32 val) #define PMT_CTRL_WUPS_MULTI 0x00000030 /* R/WC */ #define PMT_CTRL_PME_IND 0x00000008 /* R/W */ #define PMT_CTRL_PME_POL 0x00000004 /* R/W */ -#define PMT_CTRL_PME_EN 0x00000002 /* R/W Not Affected by SW Reset */ + /* R/W Not Affected by SW Reset */ +#define PMT_CTRL_PME_EN 0x00000002 #define PMT_CTRL_READY 0x00000001 /* RO */ -#define GPIO_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x88) +#define GPIO_CFG 0x88 #define GPIO_CFG_LED3_EN 0x40000000 /* R/W */ #define GPIO_CFG_LED2_EN 0x20000000 /* R/W */ #define GPIO_CFG_LED1_EN 0x10000000 /* R/W */ @@ -269,23 +280,23 @@ static inline void smc911x_reg_write(u32 addr, u32 val) #define GPIO_CFG_GPIOD1 0x00000002 /* R/W */ #define GPIO_CFG_GPIOD0 0x00000001 /* R/W */ -#define GPT_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x8C) +#define GPT_CFG 0x8C #define GPT_CFG_TIMER_EN 0x20000000 /* R/W */ #define GPT_CFG_GPT_LOAD 0x0000FFFF /* R/W */ -#define GPT_CNT (CONFIG_DRIVER_SMC911X_BASE + 0x90) +#define GPT_CNT 0x90 #define GPT_CNT_GPT_CNT 0x0000FFFF /* RO */ -#define ENDIAN (CONFIG_DRIVER_SMC911X_BASE + 0x98) -#define FREE_RUN (CONFIG_DRIVER_SMC911X_BASE + 0x9C) -#define RX_DROP (CONFIG_DRIVER_SMC911X_BASE + 0xA0) -#define MAC_CSR_CMD (CONFIG_DRIVER_SMC911X_BASE + 0xA4) +#define ENDIAN 0x98 +#define FREE_RUN 0x9C +#define RX_DROP 0xA0 +#define MAC_CSR_CMD 0xA4 #define MAC_CSR_CMD_CSR_BUSY 0x80000000 /* Self Clearing */ #define MAC_CSR_CMD_R_NOT_W 0x40000000 /* R/W */ #define MAC_CSR_CMD_CSR_ADDR 0x000000FF /* R/W */ -#define MAC_CSR_DATA (CONFIG_DRIVER_SMC911X_BASE + 0xA8) -#define AFC_CFG (CONFIG_DRIVER_SMC911X_BASE + 0xAC) +#define MAC_CSR_DATA 0xA8 +#define AFC_CFG 0xAC #define AFC_CFG_AFC_HI 0x00FF0000 /* R/W */ #define AFC_CFG_AFC_LO 0x0000FF00 /* R/W */ #define AFC_CFG_BACK_DUR 0x000000F0 /* R/W */ @@ -294,7 +305,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val) #define AFC_CFG_FCADD 0x00000002 /* R/W */ #define AFC_CFG_FCANY 0x00000001 /* R/W */ -#define E2P_CMD (CONFIG_DRIVER_SMC911X_BASE + 0xB0) +#define E2P_CMD 0xB0 #define E2P_CMD_EPC_BUSY 0x80000000 /* Self Clearing */ #define E2P_CMD_EPC_CMD 0x70000000 /* R/W */ #define E2P_CMD_EPC_CMD_READ 0x00000000 /* R/W */ @@ -309,7 +320,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val) #define E2P_CMD_MAC_ADDR_LOADED 0x00000100 /* RO */ #define E2P_CMD_EPC_ADDR 0x000000FF /* R/W */ -#define E2P_DATA (CONFIG_DRIVER_SMC911X_BASE + 0xB4) +#define E2P_DATA 0xB4 #define E2P_DATA_EEPROM_DATA 0x000000FF /* R/W */ /* end of LAN register offsets and bit definitions */ @@ -382,6 +393,7 @@ static inline void smc911x_reg_write(u32 addr, u32 val) #define CHIP_9216 0x116a #define CHIP_9217 0x117a #define CHIP_9218 0x118a +#define CHIP_9221 0x9221 struct chip_id { u16 id; @@ -398,44 +410,43 @@ static const struct chip_id chip_ids[] = { { CHIP_9216, "LAN9216" }, { CHIP_9217, "LAN9217" }, { CHIP_9218, "LAN9218" }, + { CHIP_9221, "LAN9221" }, { 0, NULL }, }; - -#define DRIVERNAME "smc911x" - -static u32 smc911x_get_mac_csr(u8 reg) +static u32 smc911x_get_mac_csr(struct eth_device *dev, u8 reg) { - while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; - smc911x_reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg); - while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + smc911x_reg_write(dev, MAC_CSR_CMD, + MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg); + while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; - return smc911x_reg_read(MAC_CSR_DATA); + return smc911x_reg_read(dev, MAC_CSR_DATA); } -static void smc911x_set_mac_csr(u8 reg, u32 data) +static void smc911x_set_mac_csr(struct eth_device *dev, u8 reg, u32 data) { - while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; - smc911x_reg_write(MAC_CSR_DATA, data); - smc911x_reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg); - while (smc911x_reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) + smc911x_reg_write(dev, MAC_CSR_DATA, data); + smc911x_reg_write(dev, MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg); + while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) ; } -static int smc911x_detect_chip(void) +static int smc911x_detect_chip(struct eth_device *dev) { unsigned long val, i; - val = smc911x_reg_read(BYTE_TEST); + val = smc911x_reg_read(dev, BYTE_TEST); if (val != 0x87654321) { printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val); return -1; } - val = smc911x_reg_read(ID_REV) >> 16; + val = smc911x_reg_read(dev, ID_REV) >> 16; for (i = 0; chip_ids[i].id != 0; i++) { if (chip_ids[i].id == val) break; } @@ -449,18 +460,19 @@ static int smc911x_detect_chip(void) return 0; } -static void smc911x_reset(void) +static void smc911x_reset(struct eth_device *dev) { int timeout; /* Take out of PM setting first */ - if (smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY) { + if (smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY) { /* Write to the bytetest will take out of powerdown */ - smc911x_reg_write(BYTE_TEST, 0x0); + smc911x_reg_write(dev, BYTE_TEST, 0x0); timeout = 10; - while (timeout-- && !(smc911x_reg_read(PMT_CTRL) & PMT_CTRL_READY)) + while (timeout-- && + !(smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY)) udelay(10); if (!timeout) { printf(DRIVERNAME @@ -470,12 +482,12 @@ static void smc911x_reset(void) } /* Disable interrupts */ - smc911x_reg_write(INT_EN, 0); + smc911x_reg_write(dev, INT_EN, 0); - smc911x_reg_write(HW_CFG, HW_CFG_SRST); + smc911x_reg_write(dev, HW_CFG, HW_CFG_SRST); timeout = 1000; - while (timeout-- && smc911x_reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) + while (timeout-- && smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) udelay(10); if (!timeout) { @@ -484,11 +496,11 @@ static void smc911x_reset(void) } /* Reset the FIFO level and flow control settings */ - smc911x_set_mac_csr(FLOW, FLOW_FCPT | FLOW_FCEN); - smc911x_reg_write(AFC_CFG, 0x0050287F); + smc911x_set_mac_csr(dev, FLOW, FLOW_FCPT | FLOW_FCEN); + smc911x_reg_write(dev, AFC_CFG, 0x0050287F); /* Set to LED outputs */ - smc911x_reg_write(GPIO_CFG, 0x70070000); + smc911x_reg_write(dev, GPIO_CFG, 0x70070000); } #endif diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 63fc02e..a9ba683 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -5,7 +5,7 @@ * terms of the GNU Public License, Version 2, incorporated * herein by reference. * - * Copyright 2004, 2007 Freescale Semiconductor, Inc. + * Copyright (C) 2004-2009 Freescale Semiconductor, Inc. * (C) Copyright 2003, Motorola, Inc. * author Andy Fleming * @@ -197,7 +197,10 @@ int tsec_init(struct eth_device *dev, bd_t * bd) for (i = 0; i < MAC_ADDR_LEN; i++) { tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i]; } - regs->macstnaddr1 = *((uint *) (tmpbuf)); + tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) | + tmpbuf[3]; + + regs->macstnaddr1 = tempval; tempval = *((uint *) (tmpbuf + 4)); @@ -1426,6 +1429,54 @@ struct phy_info phy_info_VSC8244 = { }, }; +struct phy_info phy_info_VSC8641 = { + 0x7043, + "Vitesse VSC8641", + 4, + (struct phy_cmd[]){ /* config */ + /* Configure some basic stuff */ + {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, + {miim_end,} + }, + (struct phy_cmd[]){ /* startup */ + /* Read the Status (2x to make sure link is right) */ + {MIIM_STATUS, miim_read, NULL}, + /* Auto-negotiate */ + {MIIM_STATUS, miim_read, &mii_parse_sr}, + /* Read the status */ + {MIIM_VSC8244_AUX_CONSTAT, miim_read, + &mii_parse_vsc8244}, + {miim_end,} + }, + (struct phy_cmd[]){ /* shutdown */ + {miim_end,} + }, +}; + +struct phy_info phy_info_VSC8221 = { + 0xfc55, + "Vitesse VSC8221", + 4, + (struct phy_cmd[]){ /* config */ + /* Configure some basic stuff */ + {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, + {miim_end,} + }, + (struct phy_cmd[]){ /* startup */ + /* Read the Status (2x to make sure link is right) */ + {MIIM_STATUS, miim_read, NULL}, + /* Auto-negotiate */ + {MIIM_STATUS, miim_read, &mii_parse_sr}, + /* Read the status */ + {MIIM_VSC8244_AUX_CONSTAT, miim_read, + &mii_parse_vsc8244}, + {miim_end,} + }, + (struct phy_cmd[]){ /* shutdown */ + {miim_end,} + }, +}; + struct phy_info phy_info_VSC8601 = { 0x00007042, "Vitesse VSC8601", @@ -1663,6 +1714,8 @@ struct phy_info *phy_info[] = { &phy_info_VSC8211, &phy_info_VSC8244, &phy_info_VSC8601, + &phy_info_VSC8641, + &phy_info_VSC8221, &phy_info_dp83865, &phy_info_rtl8211b, &phy_info_generic, /* must be last; has ID 0 and 32 bit mask */ diff --git a/drivers/net/uli526x.c b/drivers/net/uli526x.c index 9ea5ac2..9477851 100644 --- a/drivers/net/uli526x.c +++ b/drivers/net/uli526x.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (C) 2007 Freescale Semiconductor, Inc. * * Author: Roy Zang <tie-fei.zang@freescale.com>, Sep, 2007 * diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index 35c82b9..82e4eed 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -403,7 +403,7 @@ int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev) PCI_DEV(dev)); break; #endif -#ifdef CONFIG_MPC834x +#if defined(CONFIG_MPC834x) && !defined(CONFIG_VME8349) case PCI_CLASS_BRIDGE_OTHER: /* * The host/PCI bridge 1 seems broken in 8349 - it presents diff --git a/drivers/mtd/nand_legacy/Makefile b/drivers/power/Makefile index a1a9cc9..dd06514 100644 --- a/drivers/mtd/nand_legacy/Makefile +++ b/drivers/power/Makefile @@ -1,6 +1,6 @@ # -# (C) Copyright 2006 -# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# Copyright (c) 2009 Wind River Systems, Inc. +# Tom Rix <Tom.Rix at windriver.com> # # See file CREDITS for list of people who contributed to this # project. @@ -12,7 +12,7 @@ # # 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 +# 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 @@ -23,21 +23,20 @@ include $(TOPDIR)/config.mk -LIB := $(obj)libnand_legacy.a +LIB := $(obj)libpower.a -ifdef CONFIG_CMD_NAND -COBJS-$(CONFIG_NAND_LEGACY) := nand_legacy.o -endif +COBJS-$(CONFIG_TWL4030_POWER) += twl4030.o COBJS := $(COBJS-y) -SRCS := $(COBJS:.o=.c) -OBJS := $(addprefix $(obj),$(COBJS)) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) all: $(LIB) $(LIB): $(obj).depend $(OBJS) $(AR) $(ARFLAGS) $@ $(OBJS) + ######################################################################### # defines $(obj).depend target @@ -45,4 +44,4 @@ include $(SRCTREE)/rules.mk sinclude $(obj).depend -######################################################################### +######################################################################## diff --git a/drivers/power/twl4030.c b/drivers/power/twl4030.c new file mode 100644 index 0000000..eb066cb --- /dev/null +++ b/drivers/power/twl4030.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2009 Wind River Systems, Inc. + * Tom Rix <Tom.Rix at windriver.com> + * + * 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 + * + * twl4030_power_reset_init is derived from code on omapzoom, + * git://git.omapzoom.com/repo/u-boot.git + * + * Copyright (C) 2007-2009 Texas Instruments, Inc. + * + * twl4030_power_init is from cpu/omap3/common.c, power_init_r + * + * (C) Copyright 2004-2008 + * Texas Instruments, <www.ti.com> + * + * Author : + * Sunil Kumar <sunilsaini05 at gmail.com> + * Shashi Ranjan <shashiranjanmca05 at gmail.com> + * + * Derived from Beagle Board and 3430 SDP code by + * Richard Woodruff <r-woodruff2 at ti.com> + * Syed Mohammed Khasim <khasim at ti.com> + * + */ + +#include <twl4030.h> + +/* + * Power Reset + */ +void twl4030_power_reset_init(void) +{ + u8 val = 0; + if (twl4030_i2c_read_u8(TWL4030_CHIP_PM_MASTER, &val, + TWL4030_PM_MASTER_P1_SW_EVENTS)) { + printf("Error:TWL4030: failed to read the power register\n"); + printf("Could not initialize hardware reset\n"); + } else { + val |= TWL4030_PM_MASTER_SW_EVENTS_STOPON_PWRON; + if (twl4030_i2c_write_u8(TWL4030_CHIP_PM_MASTER, val, + TWL4030_PM_MASTER_P1_SW_EVENTS)) { + printf("Error:TWL4030: failed to write the power register\n"); + printf("Could not initialize hardware reset\n"); + } + } +} + + +/* + * Power Init + */ +#define DEV_GRP_P1 0x20 +#define VAUX3_VSEL_28 0x03 +#define DEV_GRP_ALL 0xE0 +#define VPLL2_VSEL_18 0x05 +#define VDAC_VSEL_18 0x03 + +void twl4030_power_init(void) +{ + unsigned char byte; + + /* set VAUX3 to 2.8V */ + byte = DEV_GRP_P1; + twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, byte, + TWL4030_PM_RECEIVER_VAUX3_DEV_GRP); + byte = VAUX3_VSEL_28; + twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, byte, + TWL4030_PM_RECEIVER_VAUX3_DEDICATED); + + /* set VPLL2 to 1.8V */ + byte = DEV_GRP_ALL; + twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, byte, + TWL4030_PM_RECEIVER_VPLL2_DEV_GRP); + byte = VPLL2_VSEL_18; + twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, byte, + TWL4030_PM_RECEIVER_VPLL2_DEDICATED); + + /* set VDAC to 1.8V */ + byte = DEV_GRP_P1; + twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, byte, + TWL4030_PM_RECEIVER_VDAC_DEV_GRP); + byte = VDAC_VSEL_18; + twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, byte, + TWL4030_PM_RECEIVER_VDAC_DEDICATED); +} + +#define VMMC1_VSEL_30 0x02 + +void twl4030_power_mmc_init(void) +{ + unsigned char byte; + + byte = DEV_GRP_P1; + twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, byte, + TWL4030_PM_RECEIVER_VMMC1_DEV_GRP); + + /* 3 Volts */ + byte = VMMC1_VSEL_30; + twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, byte, + TWL4030_PM_RECEIVER_VMMC1_DEDICATED); +} diff --git a/drivers/serial/arm_dcc.c b/drivers/serial/arm_dcc.c index dca73b9..7b5ecb5 100644 --- a/drivers/serial/arm_dcc.c +++ b/drivers/serial/arm_dcc.c @@ -27,7 +27,7 @@ */ #include <common.h> -#include <devices.h> +#include <stdio_dev.h> #if defined(CONFIG_CPU_V6) /* @@ -148,7 +148,7 @@ int arm_dcc_tstc(void) } #ifdef CONFIG_ARM_DCC_MULTI -static device_t arm_dcc_dev; +static struct stdio_dev arm_dcc_dev; int drv_arm_dcc_init(void) { @@ -165,6 +165,6 @@ int drv_arm_dcc_init(void) arm_dcc_dev.putc = arm_dcc_putc; /* 'putc' function */ arm_dcc_dev.puts = arm_dcc_puts; /* 'puts' function */ - return device_register(&arm_dcc_dev); + return stdio_register(&arm_dcc_dev); } #endif diff --git a/drivers/serial/usbtty.c b/drivers/serial/usbtty.c index f711d0b..cffd5a2 100644 --- a/drivers/serial/usbtty.c +++ b/drivers/serial/usbtty.c @@ -24,7 +24,7 @@ #include <common.h> #include <config.h> #include <circbuf.h> -#include <devices.h> +#include <stdio_dev.h> #include "usbtty.h" #include "usb_cdc_acm.h" #include "usbdescriptors.h" @@ -70,7 +70,7 @@ static circbuf_t usbtty_output; /* * Instance variables */ -static device_t usbttydev; +static struct stdio_dev usbttydev; static struct usb_device_instance device_instance[1]; static struct usb_bus_instance bus_instance[1]; static struct usb_configuration_instance config_instance[NUM_CONFIGS]; @@ -570,7 +570,7 @@ int drv_usbtty_init (void) usbttydev.putc = usbtty_putc; /* 'putc' function */ usbttydev.puts = usbtty_puts; /* 'puts' function */ - rc = device_register (&usbttydev); + rc = stdio_register (&usbttydev); return (rc == 0) ? 1 : rc; } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 423ea5d..324c308 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -550,9 +550,9 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, req->requesttype, req->requesttype, le16_to_cpu(req->value), le16_to_cpu(req->index)); - typeReq = req->request << 8 | req->requesttype; + typeReq = req->request | req->requesttype << 8; - switch (le16_to_cpu(typeReq)) { + switch (typeReq) { case DeviceRequest | USB_REQ_GET_DESCRIPTOR: switch (le16_to_cpu(req->value) >> 8) { case USB_DT_DEVICE: diff --git a/drivers/usb/host/ehci-kirkwood.c b/drivers/usb/host/ehci-kirkwood.c index 64997b8..5570fc6 100644 --- a/drivers/usb/host/ehci-kirkwood.c +++ b/drivers/usb/host/ehci-kirkwood.c @@ -105,4 +105,3 @@ int ehci_hcd_stop(void) { return 0; } - diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c index 19d978b..4ca94cb 100644 --- a/drivers/usb/musb/musb_hcd.c +++ b/drivers/usb/musb/musb_hcd.c @@ -801,7 +801,7 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, */ void usb_event_poll() { - device_t *dev; + struct stdio_dev *dev; struct usb_device *usb_kbd_dev; struct usb_interface_descriptor *iface; struct usb_endpoint_descriptor *ep; @@ -809,7 +809,7 @@ void usb_event_poll() int maxp; /* Get the pointer to USB Keyboard device pointer */ - dev = device_get_by_name("usbkbd"); + dev = stdio_get_by_name("usbkbd"); usb_kbd_dev = (struct usb_device *)dev->priv; iface = &usb_kbd_dev->config.if_desc[0]; ep = &iface->ep_desc[0]; diff --git a/drivers/usb/musb/musb_hcd.h b/drivers/usb/musb/musb_hcd.h index b7f571d..17e9091 100644 --- a/drivers/usb/musb/musb_hcd.h +++ b/drivers/usb/musb/musb_hcd.h @@ -26,7 +26,7 @@ #include "musb_core.h" #ifdef CONFIG_USB_KEYBOARD -#include <devices.h> +#include <stdio_dev.h> extern unsigned char new[]; #endif diff --git a/drivers/video/Makefile b/drivers/video/Makefile index bc00852..bb6b5a0 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -36,6 +36,7 @@ COBJS-$(CONFIG_VIDEO_SED13806) += sed13806.o COBJS-$(CONFIG_SED156X) += sed156x.o COBJS-$(CONFIG_VIDEO_SM501) += sm501.o COBJS-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o +COBJS-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o COBJS-y += videomodes.o COBJS := $(COBJS-y) diff --git a/drivers/video/bus_vcxk.c b/drivers/video/bus_vcxk.c new file mode 100644 index 0000000..b3b53e1 --- /dev/null +++ b/drivers/video/bus_vcxk.c @@ -0,0 +1,440 @@ +/* + * (C) Copyright 2005-2009 + * Jens Scharsig @ BuS Elektronik GmbH & Co. KG, <esw@bus-elektronik.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <bmp_layout.h> +#include <asm/io.h> + +vu_char *vcxk_bws = ((vu_char *) (CONFIG_SYS_VCXK_BASE)); +vu_short *vcxk_bws_word = ((vu_short *)(CONFIG_SYS_VCXK_BASE)); +vu_long *vcxk_bws_long = ((vu_long *) (CONFIG_SYS_VCXK_BASE)); + +#ifdef CONFIG_AT91RM9200 + #include <asm/arch/hardware.h> + #ifndef VCBITMASK + #define VCBITMASK(bitno) (0x0001 << (bitno % 16)) + #endif + #define VCXK_INIT_PIN(PORT, PIN, DDR, I0O1) \ + ((AT91PS_PIO) PORT)->PIO_PER = PIN; \ + ((AT91PS_PIO) PORT)->DDR = PIN; \ + ((AT91PS_PIO) PORT)->PIO_MDDR = PIN; \ + if (!I0O1) ((AT91PS_PIO) PORT)->PIO_PPUER = PIN; + + #define VCXK_SET_PIN(PORT, PIN) ((AT91PS_PIO) PORT)->PIO_SODR = PIN; + #define VCXK_CLR_PIN(PORT, PIN) ((AT91PS_PIO) PORT)->PIO_CODR = PIN; + + #define VCXK_ACKNOWLEDGE \ + (!(((AT91PS_PIO) CONFIG_SYS_VCXK_ACKNOWLEDGE_PORT)->\ + PIO_PDSR & CONFIG_SYS_VCXK_ACKNOWLEDGE_PIN)) + +#elif defined(CONFIG_MCF52x2) + #include <asm/m5282.h> + #ifndef VCBITMASK + #define VCBITMASK(bitno) (0x8000 >> (bitno % 16)) + #endif + + #define VCXK_INIT_PIN(PORT, PIN, DDR, I0O1) \ + if (I0O1) DDR |= PIN; else DDR &= ~PIN; + + #define VCXK_SET_PIN(PORT, PIN) PORT |= PIN; + #define VCXK_CLR_PIN(PORT, PIN) PORT &= ~PIN; + + #define VCXK_ACKNOWLEDGE \ + (!(CONFIG_SYS_VCXK_ACKNOWLEDGE_PORT & \ + CONFIG_SYS_VCXK_ACKNOWLEDGE_PIN)) + +#else + #error no vcxk support for selected ARCH +#endif + +#define VCXK_DISABLE\ + VCXK_SET_PIN(CONFIG_SYS_VCXK_ENABLE_PORT, CONFIG_SYS_VCXK_ENABLE_PIN) +#define VCXK_ENABLE\ + VCXK_CLR_PIN(CONFIG_SYS_VCXK_ENABLE_PORT, CONFIG_SYS_VCXK_ENABLE_PIN) + +#ifndef CONFIG_SYS_VCXK_DOUBLEBUFFERED + #define VCXK_BWS(x, data) vcxk_bws[x] = data; + #define VCXK_BWS_WORD_SET(x, mask) vcxk_bws_word[x] |= mask; + #define VCXK_BWS_WORD_CLEAR(x, mask) vcxk_bws_word[x] &= ~mask; + #define VCXK_BWS_LONG(x, data) vcxk_bws_long[x] = data; +#else + u_char double_bws[16384]; + u_short *double_bws_word; + u_long *double_bws_long; + #define VCXK_BWS(x,data) \ + double_bws[x] = data; vcxk_bws[x] = data; + #define VCXK_BWS_WORD_SET(x,mask) \ + double_bws_word[x] |= mask; \ + vcxk_bws_word[x] = double_bws_word[x]; + #define VCXK_BWS_WORD_CLEAR(x,mask) \ + double_bws_word[x] &= ~mask; \ + vcxk_bws_word[x] = double_bws_word[x]; + #define VCXK_BWS_LONG(x,data) \ + double_bws_long[x] = data; vcxk_bws_long[x] = data; +#endif + +#define VC4K16_Bright1 vcxk_bws_word[0x20004 / 2] +#define VC4K16_Bright2 vcxk_bws_word[0x20006 / 2] +#define VC2K_Bright vcxk_bws[0x8000] +#define VC8K_BrightH vcxk_bws[0xC000] +#define VC8K_BrightL vcxk_bws[0xC001] + +vu_char VC4K16; + +u_long display_width; +u_long display_height; +u_long display_bwidth; + +ulong search_vcxk_driver(void); +void vcxk_cls(void); +void vcxk_setbrightness(unsigned int side, short brightness); +int vcxk_request(void); +int vcxk_acknowledge_wait(void); +void vcxk_clear(void); + +/* + ****f* bus_vcxk/vcxk_init + * FUNCTION + * initialalize Video Controller + * PARAMETERS + * width visible display width in pixel + * height visible display height in pixel + *** + */ + +int vcxk_init(unsigned long width, unsigned long height) +{ +#ifdef CONFIG_SYS_VCXK_RESET_PORT + VCXK_INIT_PIN(CONFIG_SYS_VCXK_RESET_PORT, + CONFIG_SYS_VCXK_RESET_PIN, CONFIG_SYS_VCXK_RESET_DDR, 1) + VCXK_SET_PIN(CONFIG_SYS_VCXK_RESET_PORT, CONFIG_SYS_VCXK_RESET_PIN); +#endif + +#ifdef CONFIG_SYS_VCXK_DOUBLEBUFFERED + double_bws_word = (u_short *)double_bws; + double_bws_long = (u_long *)double_bws; + debug("%lx %lx %lx \n", double_bws, double_bws_word, double_bws_long); +#endif + display_width = width; + display_height = height; +#if (CONFIG_SYS_VCXK_DEFAULT_LINEALIGN == 4) + display_bwidth = ((width + 31) / 8) & ~0x3; +#elif (CONFIG_SYS_VCXK_DEFAULT_LINEALIGN == 2) + display_bwidth = ((width + 15) / 8) & ~0x1; +#else + #error CONFIG_SYS_VCXK_DEFAULT_LINEALIGN is invalid +#endif + debug("linesize ((%d + 15) / 8 & ~0x1) = %d\n", + display_width, display_bwidth); + +#ifdef CONFIG_SYS_VCXK_AUTODETECT + VC4K16 = 0; + vcxk_bws_long[1] = 0x0; + vcxk_bws_long[1] = 0x55AAAA55; + vcxk_bws_long[5] = 0x0; + if (vcxk_bws_long[1] == 0x55AAAA55) + VC4K16 = 1; +#else + VC4K16 = 1; + debug("No autodetect: use vc4k\n"); +#endif + + VCXK_INIT_PIN(CONFIG_SYS_VCXK_INVERT_PORT, + CONFIG_SYS_VCXK_INVERT_PIN, CONFIG_SYS_VCXK_INVERT_DDR, 1) + VCXK_SET_PIN(CONFIG_SYS_VCXK_INVERT_PORT, CONFIG_SYS_VCXK_INVERT_PIN) + + VCXK_SET_PIN(CONFIG_SYS_VCXK_REQUEST_PORT, CONFIG_SYS_VCXK_REQUEST_PIN); + VCXK_INIT_PIN(CONFIG_SYS_VCXK_REQUEST_PORT, + CONFIG_SYS_VCXK_REQUEST_PIN, CONFIG_SYS_VCXK_REQUEST_DDR, 1) + + VCXK_INIT_PIN(CONFIG_SYS_VCXK_ACKNOWLEDGE_PORT, + CONFIG_SYS_VCXK_ACKNOWLEDGE_PIN, + CONFIG_SYS_VCXK_ACKNOWLEDGE_DDR, 0) + + VCXK_DISABLE; + VCXK_INIT_PIN(CONFIG_SYS_VCXK_ENABLE_PORT, + CONFIG_SYS_VCXK_ENABLE_PIN, CONFIG_SYS_VCXK_ENABLE_DDR, 1) + + vcxk_cls(); + vcxk_cls(); /* clear second/hidden page */ + + vcxk_setbrightness(3, 1000); + VCXK_ENABLE; + return 1; +} + +/* + ****f* bus_vcxk/vcxk_setpixel + * FUNCTION + * set the pixel[x,y] with the given color + * PARAMETER + * x pixel colum + * y pixel row + * color <0x40 off/black + * >0x40 on + *** + */ + +void vcxk_setpixel(int x, int y, unsigned long color) +{ + vu_short dataptr; + + if ((x < display_width) && (y < display_height)) { + dataptr = ((x / 16)) + (y * (display_bwidth >> 1)); + + color = ((color >> 16) & 0xFF) | + ((color >> 8) & 0xFF) | (color & 0xFF); + + if (color > 0x40) { + VCXK_BWS_WORD_SET(dataptr, VCBITMASK(x)); + } else { + VCXK_BWS_WORD_CLEAR(dataptr, VCBITMASK(x)); + } + } +} + +/* + ****f* bus_vcxk/vcxk_loadimage + * FUNCTION + * copies a binary image to display memory + *** + */ + +void vcxk_loadimage(ulong source) +{ + int cnt; + vcxk_acknowledge_wait(); + if (VC4K16) { + for (cnt = 0; cnt < (16384 / 4); cnt++) { + VCXK_BWS_LONG(cnt, (*(ulong *) source)); + source = source + 4; + } + } else { + for (cnt = 0; cnt < 16384; cnt++) { + VCXK_BWS_LONG(cnt*2, (*(vu_char *) source)); + source++; + } + } + vcxk_request(); +} + +/* + ****f* bus_vcxk/vcxk_cls + * FUNCTION + * clear the display + *** + */ + +void vcxk_cls(void) +{ + vcxk_acknowledge_wait(); + vcxk_clear(); + vcxk_request(); +} + +/* + ****f* bus_vcxk/vcxk_clear(void) + * FUNCTION + * clear the display memory + *** + */ + +void vcxk_clear(void) +{ + int cnt; + + for (cnt = 0; cnt < (16384 / 4); cnt++) { + VCXK_BWS_LONG(cnt, 0) + } +} + +/* + ****f* bus_vcxk/vcxk_setbrightness + * FUNCTION + * set the display brightness + * PARAMETER + * side 1 set front side brightness + * 2 set back side brightness + * 3 set brightness for both sides + * brightness 0..1000 + *** + */ + +void vcxk_setbrightness(unsigned int side, short brightness) +{ + if (VC4K16) { + if ((side == 0) || (side & 0x1)) + VC4K16_Bright1 = brightness + 23; + if ((side == 0) || (side & 0x2)) + VC4K16_Bright2 = brightness + 23; + } else { + VC2K_Bright = (brightness >> 4) + 2; + VC8K_BrightH = (brightness + 23) >> 8; + VC8K_BrightL = (brightness + 23) & 0xFF; + } +} + +/* + ****f* bus_vcxk/vcxk_request + * FUNCTION + * requests viewing of display memory + *** + */ + +int vcxk_request(void) +{ + VCXK_CLR_PIN(CONFIG_SYS_VCXK_REQUEST_PORT, + CONFIG_SYS_VCXK_REQUEST_PIN) + VCXK_SET_PIN(CONFIG_SYS_VCXK_REQUEST_PORT, + CONFIG_SYS_VCXK_REQUEST_PIN); + return 1; +} + +/* + ****f* bus_vcxk/vcxk_acknowledge_wait + * FUNCTION + * wait for acknowledge viewing requests + *** + */ + +int vcxk_acknowledge_wait(void) +{ + while (VCXK_ACKNOWLEDGE) + ; + return 1; +} + +/* + ****f* bus_vcxk/vcxk_draw_mono + * FUNCTION + * copies a monochrom bitmap (BMP-Format) from given memory + * PARAMETER + * dataptr pointer to bitmap + * x output bitmap @ columne + * y output bitmap @ row + *** + */ + +void vcxk_draw_mono(unsigned char *dataptr, unsigned long linewidth, + unsigned long cp_width, unsigned long cp_height) +{ + unsigned char *lineptr; + unsigned long xcnt, ycnt; + + for (ycnt = cp_height; ycnt > 0; ycnt--) { + lineptr = dataptr; + for (xcnt = 0; xcnt < cp_width; xcnt++) { + if ((*lineptr << (xcnt % 8)) & 0x80) + vcxk_setpixel(xcnt, ycnt - 1, 0xFFFFFF); + else + vcxk_setpixel(xcnt, ycnt-1, 0); + + if ((xcnt % 8) == 7) + lineptr++; + } /* endfor xcnt */ + dataptr = dataptr + linewidth; + } /* endfor ycnt */ +} + +/* + ****f* bus_vcxk/vcxk_display_bitmap + * FUNCTION + * copies a bitmap (BMP-Format) to the given position + * PARAMETER + * addr pointer to bitmap + * x output bitmap @ columne + * y output bitmap @ row + *** + */ + +int vcxk_display_bitmap(ulong addr, int x, int y) +{ + bmp_image_t *bmp; + unsigned long width; + unsigned long height; + unsigned long bpp; + unsigned long compression; + + unsigned long lw; + + unsigned long c_width; + unsigned long c_height; + unsigned char *dataptr; + unsigned char *lineptr; + + bmp = (bmp_image_t *) addr; + if ((bmp->header.signature[0] == 'B') && + (bmp->header.signature[1] == 'M')) { + compression = le32_to_cpu(bmp->header.compression); + width = le32_to_cpu(bmp->header.width); + height = le32_to_cpu(bmp->header.height); + bpp = le16_to_cpu(bmp->header.bit_count); + + dataptr = (unsigned char *) bmp + + le32_to_cpu(bmp->header.data_offset); + + if (display_width < (width + x)) + c_width = display_width - x; + else + c_width = width; + if (display_height < (height + y)) + c_height = display_height - y; + else + c_height = height; + + lw = (((width + 7) / 8) + 3) & ~0x3; + + if (c_height < height) + dataptr = dataptr + lw * (height - c_height); + switch (bpp) { + case 1: + vcxk_draw_mono(dataptr, lw, c_width, c_height); + break; + default: + printf("Error: %ld bit per pixel " + "not supported by VCxK\n", bpp); + return 0; + } + } else { + printf("Error: no valid bmp at %lx\n", (ulong) bmp); + return 0; + } + return 1; +} + +/* + ****f* bus_vcxk/video_display_bitmap + *** + */ + +int video_display_bitmap(ulong addr, int x, int y) +{ + vcxk_acknowledge_wait(); + if (vcxk_display_bitmap(addr, x, y)) { + vcxk_request(); + return 0; + } + return 1; +} + +/* EOF */ diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index bcafb27..fbc4df9 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -183,7 +183,7 @@ CONFIG_VIDEO_HW_CURSOR: - Uses the hardware cursor capability of the #include <version.h> #include <linux/types.h> -#include <devices.h> +#include <stdio_dev.h> #include <video_font.h> #if defined(CONFIG_CMD_DATE) @@ -193,6 +193,11 @@ CONFIG_VIDEO_HW_CURSOR: - Uses the hardware cursor capability of the #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN) #include <watchdog.h> #include <bmp_layout.h> + +#ifdef CONFIG_SPLASH_SCREEN_ALIGN +#define BMP_ALIGN_CENTER 0x7FFF +#endif + #endif /*****************************************************************************/ @@ -877,6 +882,18 @@ int video_display_bitmap (ulong bmp_image, int x, int y) padded_line = (((width * bpp + 7) / 8) + 3) & ~0x3; +#ifdef CONFIG_SPLASH_SCREEN_ALIGN + if (x == BMP_ALIGN_CENTER) + x = max(0, (VIDEO_VISIBLE_COLS - width) / 2); + else if (x < 0) + x = max(0, VIDEO_VISIBLE_COLS - width + x + 1); + + if (y == BMP_ALIGN_CENTER) + y = max(0, (VIDEO_VISIBLE_ROWS - height) / 2); + else if (y < 0) + y = max(0, VIDEO_VISIBLE_ROWS - height + y + 1); +#endif /* CONFIG_SPLASH_SCREEN_ALIGN */ + if ((x + width) > VIDEO_VISIBLE_COLS) width = VIDEO_VISIBLE_COLS - x; if ((y + height) > VIDEO_VISIBLE_ROWS) @@ -1188,9 +1205,26 @@ static void *video_logo (void) ulong addr; if ((s = getenv ("splashimage")) != NULL) { + int x = 0, y = 0; + addr = simple_strtoul (s, NULL, 16); +#ifdef CONFIG_SPLASH_SCREEN_ALIGN + if ((s = getenv ("splashpos")) != NULL) { + if (s[0] == 'm') + x = BMP_ALIGN_CENTER; + else + x = simple_strtol (s, NULL, 0); + + if ((s = strchr (s + 1, ',')) != NULL) { + if (s[1] == 'm') + y = BMP_ALIGN_CENTER; + else + y = simple_strtol (s + 1, NULL, 0); + } + } +#endif /* CONFIG_SPLASH_SCREEN_ALIGN */ - if (video_display_bitmap (addr, 0, 0) == 0) { + if (video_display_bitmap (addr, x, y) == 0) { return ((void *) (video_fb_address)); } } @@ -1344,7 +1378,7 @@ int board_video_skip(void) __attribute__((weak, alias("__board_video_skip"))); int drv_video_init (void) { int skip_dev_init; - device_t console_dev; + struct stdio_dev console_dev; /* Check if video initialization should be skipped */ if (board_video_skip()) @@ -1378,7 +1412,7 @@ int drv_video_init (void) console_dev.getc = VIDEO_GETC_FCT; /* 'getc' function */ #endif /* CONFIG_VGA_AS_SINGLE_DEVICE */ - if (device_register (&console_dev) != 0) + if (stdio_register (&console_dev) != 0) return 0; /* Return success */ diff --git a/drivers/video/mb862xx.c b/drivers/video/mb862xx.c index 01eda55..a8676cc 100644 --- a/drivers/video/mb862xx.c +++ b/drivers/video/mb862xx.c @@ -37,6 +37,7 @@ #if defined(CONFIG_POST) #include <post.h> #endif + /* * Graphic Device */ @@ -65,74 +66,74 @@ unsigned int fr_div[] = { 0x00000f00, 0x00000900, 0x00000500 }; #define rd_io in32r #define wr_io out32r #else -#define rd_io(addr) in_be32((volatile unsigned*)(addr)) -#define wr_io(addr,val) out_be32((volatile unsigned*)(addr), (val)) +#define rd_io(addr) in_be32((volatile unsigned *)(addr)) +#define wr_io(addr, val) out_be32((volatile unsigned *)(addr), (val)) #endif -#define HOST_RD_REG(off) rd_io((pGD->frameAdrs + 0x01fc0000 + (off))) -#define HOST_WR_REG(off, val) wr_io((pGD->frameAdrs + 0x01fc0000 + (off)), (val)) -#define DISP_RD_REG(off) rd_io((pGD->frameAdrs + 0x01fd0000 + (off))) -#define DISP_WR_REG(off, val) wr_io((pGD->frameAdrs + 0x01fd0000 + (off)), (val)) -#define DE_RD_REG(off) rd_io((pGD->dprBase + (off))) -#define DE_WR_REG(off, val) wr_io((pGD->dprBase + (off)), (val)) +#define HOST_RD_REG(off) rd_io((dev->frameAdrs + GC_HOST_BASE + (off))) +#define HOST_WR_REG(off, val) wr_io((dev->frameAdrs + GC_HOST_BASE + (off)), \ + (val)) +#define DISP_RD_REG(off) rd_io((dev->frameAdrs + GC_DISP_BASE + (off))) +#define DISP_WR_REG(off, val) wr_io((dev->frameAdrs + GC_DISP_BASE + (off)), \ + (val)) +#define DE_RD_REG(off) rd_io((dev->dprBase + (off))) +#define DE_WR_REG(off, val) wr_io((dev->dprBase + (off)), (val)) #if defined(CONFIG_VIDEO_CORALP) -#define DE_WR_FIFO(val) wr_io((pGD->dprBase + (0x8400)), (val)) +#define DE_WR_FIFO(val) wr_io((dev->dprBase + (GC_GEO_FIFO)), (val)) #else -#define DE_WR_FIFO(val) wr_io((pGD->dprBase + (0x04a0)), (val)) +#define DE_WR_FIFO(val) wr_io((dev->dprBase + (GC_FIFO)), (val)) #endif -#define L0PAL_RD_REG(idx, val) rd_io((pGD->frameAdrs + 0x01fd0400 + ((idx)<<2))) -#define L0PAL_WR_REG(idx, val) wr_io((pGD->frameAdrs + 0x01fd0400 + ((idx)<<2)), (val)) -#define L1PAL_RD_REG(idx, val) rd_io((pGD->frameAdrs + 0x01fd0800 + ((idx)<<2))) -#define L1PAL_WR_REG(idx, val) wr_io((pGD->frameAdrs + 0x01fd0800 + ((idx)<<2)), (val)) -#define L2PAL_RD_REG(idx, val) rd_io((pGD->frameAdrs + 0x01fd1000 + ((idx)<<2))) -#define L2PAL_WR_REG(idx, val) wr_io((pGD->frameAdrs + 0x01fd1000 + ((idx)<<2)), (val)) -#define L3PAL_RD_REG(idx, val) rd_io((pGD->frameAdrs + 0x01fd1400 + ((idx)<<2))) -#define L3PAL_WR_REG(idx, val) wr_io((pGD->frameAdrs + 0x01fd1400 + ((idx)<<2)), (val)) +#define L0PAL_WR_REG(idx, val) wr_io((dev->frameAdrs + \ + (GC_DISP_BASE | GC_L0PAL0) + \ + ((idx) << 2)), (val)) -static void gdc_sw_reset(void) +static void gdc_sw_reset (void) { - GraphicDevice *pGD = (GraphicDevice *)&mb862xx; - HOST_WR_REG (0x002c, 0x00000001); + GraphicDevice *dev = &mb862xx; + + HOST_WR_REG (GC_SRST, 0x1); udelay (500); video_hw_init (); } -static void de_wait(void) +static void de_wait (void) { - GraphicDevice *pGD = (GraphicDevice *)&mb862xx; + GraphicDevice *dev = &mb862xx; int lc = 0x10000; - /* Sync with software writes to framebuffer, - try to reset if engine locked */ - while (DE_RD_REG (0x0400) & 0x00000131) + /* + * Sync with software writes to framebuffer, + * try to reset if engine locked + */ + while (DE_RD_REG (GC_CTR) & 0x00000131) if (lc-- < 0) { gdc_sw_reset (); - printf ("gdc reset done after drawing engine lock...\n"); + puts ("gdc reset done after drawing engine lock.\n"); break; } } -static void de_wait_slots(int slots) +static void de_wait_slots (int slots) { - GraphicDevice *pGD = (GraphicDevice *)&mb862xx; + GraphicDevice *dev = &mb862xx; int lc = 0x10000; /* Wait for free fifo slots */ - while (DE_RD_REG (0x0408) < slots) + while (DE_RD_REG (GC_IFCNT) < slots) if (lc-- < 0) { gdc_sw_reset (); - printf ("gdc reset done after drawing engine lock...\n"); + puts ("gdc reset done after drawing engine lock.\n"); break; } } #if !defined(CONFIG_VIDEO_CORALP) -static void board_disp_init(void) +static void board_disp_init (void) { - GraphicDevice *pGD = (GraphicDevice *)&mb862xx; + GraphicDevice *dev = &mb862xx; const gdc_regs *regs = board_get_regs (); while (regs->index) { @@ -147,69 +148,69 @@ static void board_disp_init(void) */ static void de_init (void) { - GraphicDevice *pGD = (GraphicDevice *)&mb862xx; - int cf = (pGD->gdfBytesPP == 1) ? 0x0000 : 0x8000; + GraphicDevice *dev = &mb862xx; + int cf = (dev->gdfBytesPP == 1) ? 0x0000 : 0x8000; - pGD->dprBase = pGD->frameAdrs + 0x01ff0000; + dev->dprBase = dev->frameAdrs + GC_DRAW_BASE; /* Setup mode and fbbase, xres, fg, bg */ de_wait_slots (2); DE_WR_FIFO (0xf1010108); DE_WR_FIFO (cf | 0x0300); - DE_WR_REG (0x0440, 0x0000); - DE_WR_REG (0x0444, pGD->winSizeX); - DE_WR_REG (0x0480, 0x0000); - DE_WR_REG (0x0484, 0x0000); + DE_WR_REG (GC_FBR, 0x0); + DE_WR_REG (GC_XRES, dev->winSizeX); + DE_WR_REG (GC_FC, 0x0); + DE_WR_REG (GC_BC, 0x0); /* Reset clipping */ - DE_WR_REG (0x0454, 0x0000); - DE_WR_REG (0x0458, pGD->winSizeX); - DE_WR_REG (0x045c, 0x0000); - DE_WR_REG (0x0460, pGD->winSizeY); + DE_WR_REG (GC_CXMIN, 0x0); + DE_WR_REG (GC_CXMAX, dev->winSizeX); + DE_WR_REG (GC_CYMIN, 0x0); + DE_WR_REG (GC_CYMAX, dev->winSizeY); /* Clear framebuffer using drawing engine */ de_wait_slots (3); DE_WR_FIFO (0x09410000); DE_WR_FIFO (0x00000000); - DE_WR_FIFO (pGD->winSizeY<<16 | pGD->winSizeX); + DE_WR_FIFO (dev->winSizeY << 16 | dev->winSizeX); /* sync with SW access to framebuffer */ de_wait (); } #if defined(CONFIG_VIDEO_CORALP) -unsigned int pci_video_init(void) +unsigned int pci_video_init (void) { - GraphicDevice *pGD = (GraphicDevice *)&mb862xx; + GraphicDevice *dev = &mb862xx; pci_dev_t devbusfn; - if ((devbusfn = pci_find_devices(supported, 0)) < 0) - { - printf ("PCI video controller not found!\n"); + if ((devbusfn = pci_find_devices (supported, 0)) < 0) { + puts ("PCI video controller not found!\n"); return 0; } /* PCI setup */ - pci_write_config_dword (devbusfn, PCI_COMMAND, (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)); - pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0, &pGD->frameAdrs); - pGD->frameAdrs = pci_mem_to_phys (devbusfn, pGD->frameAdrs); + pci_write_config_dword (devbusfn, PCI_COMMAND, + (PCI_COMMAND_MEMORY | PCI_COMMAND_IO)); + pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0, &dev->frameAdrs); + dev->frameAdrs = pci_mem_to_phys (devbusfn, dev->frameAdrs); - if (pGD->frameAdrs == 0) { - printf ("PCI config: failed to get base address\n"); + if (dev->frameAdrs == 0) { + puts ("PCI config: failed to get base address\n"); return 0; } - pGD->pciBase = pGD->frameAdrs; + dev->pciBase = dev->frameAdrs; /* Setup clocks and memory mode for Coral-P Eval. Board */ - HOST_WR_REG (0x0038, 0x00090000); + HOST_WR_REG (GC_CCF, 0x00090000); udelay (200); - HOST_WR_REG (0xfffc, 0x11d7fa13); + HOST_WR_REG (GC_MMR, 0x11d7fa13); udelay (100); - return pGD->frameAdrs; + return dev->frameAdrs; } unsigned int card_init (void) { - GraphicDevice *pGD = (GraphicDevice *)&mb862xx; + GraphicDevice *dev = &mb862xx; unsigned int cf, videomode, div = 0; unsigned long t1, hsync, vsync; char *penv; @@ -217,19 +218,18 @@ unsigned int card_init (void) struct ctfb_res_modes *res_mode; struct ctfb_res_modes var_mode; - memset (pGD, 0, sizeof (GraphicDevice)); + memset (dev, 0, sizeof (GraphicDevice)); - if (!pci_video_init ()) { + if (!pci_video_init ()) return 0; - } - printf ("CoralP\n"); + puts ("CoralP\n"); tmp = 0; videomode = 0x310; /* get video mode via environment */ if ((penv = getenv ("videomode")) != NULL) { - /* deceide if it is a string */ + /* decide if it is a string */ if (penv[0] <= '9') { videomode = (int) simple_strtoul (penv, NULL, 16); tmp = 1; @@ -237,28 +237,28 @@ unsigned int card_init (void) } else { tmp = 1; } + if (tmp) { - /* parameter are vesa modes */ - /* search params */ + /* parameter are vesa modes, search params */ for (i = 0; i < VESA_MODES_COUNT; i++) { if (vesa_modes[i].vesanr == videomode) break; } if (i == VESA_MODES_COUNT) { - printf ("\tno VESA Mode found, switching to mode 0x%x \n", videomode); + printf ("\tno VESA Mode found, fallback to mode 0x%x\n", + videomode); i = 0; } - res_mode = - (struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].resindex]; + res_mode = (struct ctfb_res_modes *) + &res_mode_init[vesa_modes[i].resindex]; if (vesa_modes[i].resindex > 2) { - printf ("\tUnsupported resolution, switching to default\n"); + puts ("\tUnsupported resolution, using default\n"); bpp = vesa_modes[1].bits_per_pixel; div = fr_div[1]; } bpp = vesa_modes[i].bits_per_pixel; div = fr_div[vesa_modes[i].resindex]; } else { - res_mode = (struct ctfb_res_modes *) &var_mode; bpp = video_get_params (res_mode, penv); } @@ -276,85 +276,97 @@ unsigned int card_init (void) vsync = 1000000000L / t1; /* fill in Graphic device struct */ - sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres, + sprintf (dev->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres, res_mode->yres, bpp, (hsync / 1000), (vsync / 1000)); - printf ("\t%s\n", pGD->modeIdent); - pGD->winSizeX = res_mode->xres; - pGD->winSizeY = res_mode->yres; - pGD->memSize = VIDEO_MEM_SIZE; + printf ("\t%s\n", dev->modeIdent); + dev->winSizeX = res_mode->xres; + dev->winSizeY = res_mode->yres; + dev->memSize = VIDEO_MEM_SIZE; switch (bpp) { case 8: - pGD->gdfIndex = GDF__8BIT_INDEX; - pGD->gdfBytesPP = 1; + dev->gdfIndex = GDF__8BIT_INDEX; + dev->gdfBytesPP = 1; break; case 15: case 16: - pGD->gdfIndex = GDF_15BIT_555RGB; - pGD->gdfBytesPP = 2; + dev->gdfIndex = GDF_15BIT_555RGB; + dev->gdfBytesPP = 2; break; default: - printf ("\t%d bpp configured, but only 8,15 and 16 supported.\n", bpp); - printf ("\tSwitching back to 15bpp\n"); - pGD->gdfIndex = GDF_15BIT_555RGB; - pGD->gdfBytesPP = 2; + printf ("\t%d bpp configured, but only 8,15 and 16 supported\n", + bpp); + puts ("\tfallback to 15bpp\n"); + dev->gdfIndex = GDF_15BIT_555RGB; + dev->gdfBytesPP = 2; } /* Setup dot clock (internal pll, division rate) */ - DISP_WR_REG (0x0100, div); + DISP_WR_REG (GC_DCM1, div); /* L0 init */ - cf = (pGD->gdfBytesPP == 1) ? 0x00000000 : 0x80000000; - DISP_WR_REG (0x0020, ((pGD->winSizeX * pGD->gdfBytesPP)/64)<<16 | - (pGD->winSizeY-1) | - cf); - DISP_WR_REG (0x0024, 0x00000000); - DISP_WR_REG (0x0028, 0x00000000); - DISP_WR_REG (0x002c, 0x00000000); - DISP_WR_REG (0x0110, 0x00000000); - DISP_WR_REG (0x0114, 0x00000000); - DISP_WR_REG (0x0118, (pGD->winSizeY-1)<<16 | pGD->winSizeX); + cf = (dev->gdfBytesPP == 1) ? 0x00000000 : 0x80000000; + DISP_WR_REG (GC_L0M, ((dev->winSizeX * dev->gdfBytesPP) / 64) << 16 | + (dev->winSizeY - 1) | cf); + DISP_WR_REG (GC_L0OA0, 0x0); + DISP_WR_REG (GC_L0DA0, 0x0); + DISP_WR_REG (GC_L0DY_L0DX, 0x0); + DISP_WR_REG (GC_L0EM, 0x0); + DISP_WR_REG (GC_L0WY_L0WX, 0x0); + DISP_WR_REG (GC_L0WH_L0WW, (dev->winSizeY - 1) << 16 | dev->winSizeX); /* Display timing init */ - DISP_WR_REG (0x0004, (pGD->winSizeX+res_mode->left_margin+res_mode->right_margin+res_mode->hsync_len-1)<<16); - DISP_WR_REG (0x0008, (pGD->winSizeX-1) << 16 | (pGD->winSizeX-1)); - DISP_WR_REG (0x000c, (res_mode->vsync_len-1)<<24|(res_mode->hsync_len-1)<<16|(pGD->winSizeX+res_mode->right_margin-1)); - DISP_WR_REG (0x0010, (pGD->winSizeY+res_mode->lower_margin+res_mode->upper_margin+res_mode->vsync_len-1)<<16); - DISP_WR_REG (0x0014, (pGD->winSizeY-1) << 16 | (pGD->winSizeY+res_mode->lower_margin-1)); - DISP_WR_REG (0x0018, 0x00000000); - DISP_WR_REG (0x001c, pGD->winSizeY << 16 | pGD->winSizeX); + DISP_WR_REG (GC_HTP_A, (dev->winSizeX + + res_mode->left_margin + + res_mode->right_margin + + res_mode->hsync_len - 1) << 16); + DISP_WR_REG (GC_HDB_HDP_A, (dev->winSizeX - 1) << 16 | + (dev->winSizeX - 1)); + DISP_WR_REG (GC_VSW_HSW_HSP_A, (res_mode->vsync_len - 1) << 24 | + (res_mode->hsync_len - 1) << 16 | + (dev->winSizeX + + res_mode->right_margin - 1)); + DISP_WR_REG (GC_VTR_A, (dev->winSizeY + res_mode->lower_margin + + res_mode->upper_margin + + res_mode->vsync_len - 1) << 16); + DISP_WR_REG (GC_VDP_VSP_A, (dev->winSizeY-1) << 16 | + (dev->winSizeY + + res_mode->lower_margin - 1)); + DISP_WR_REG (GC_WY_WX, 0x0); + DISP_WR_REG (GC_WH_WW, dev->winSizeY << 16 | dev->winSizeX); /* Display enable, L0 layer */ - DISP_WR_REG (0x0100, 0x80010000 | div); + DISP_WR_REG (GC_DCM1, 0x80010000 | div); - return pGD->frameAdrs; + return dev->frameAdrs; } #endif void *video_hw_init (void) { - GraphicDevice *pGD = (GraphicDevice *)&mb862xx; + GraphicDevice *dev = &mb862xx; - printf ("Video: Fujitsu "); + puts ("Video: Fujitsu "); - memset (pGD, 0, sizeof (GraphicDevice)); + memset (dev, 0, sizeof (GraphicDevice)); #if defined(CONFIG_VIDEO_CORALP) - if (card_init () == 0) { - return (NULL); - } + if (card_init () == 0) + return NULL; #else - /* Preliminary init of the onboard graphic controller, - retrieve base address */ - if ((pGD->frameAdrs = board_video_init ()) == 0) { - printf ("Controller not found!\n"); - return (NULL); + /* + * Preliminary init of the onboard graphic controller, + * retrieve base address + */ + if ((dev->frameAdrs = board_video_init ()) == 0) { + puts ("Controller not found!\n"); + return NULL; } else - printf("Lime\n"); + puts ("Lime\n"); #endif de_init (); #if !defined(CONFIG_VIDEO_CORALP) - board_disp_init(); + board_disp_init (); #endif #if (defined(CONFIG_LWMON5) || \ @@ -363,15 +375,16 @@ void *video_hw_init (void) board_backlight_switch (1); #endif - return pGD; + return dev; } /* * Set a RGB color in the LUT */ -void video_set_lut (unsigned int index, unsigned char r, unsigned char g, unsigned char b) +void video_set_lut (unsigned int index, unsigned char r, + unsigned char g, unsigned char b) { - GraphicDevice *pGD = (GraphicDevice *)&mb862xx; + GraphicDevice *dev = &mb862xx; L0PAL_WR_REG (index, (r << 16) | (g << 8) | (b)); } @@ -379,24 +392,26 @@ void video_set_lut (unsigned int index, unsigned char r, unsigned char g, unsign /* * Drawing engine Fill and BitBlt screen region */ -void video_hw_rectfill (unsigned int bpp, unsigned int dst_x, unsigned int dst_y, - unsigned int dim_x, unsigned int dim_y, unsigned int color) +void video_hw_rectfill (unsigned int bpp, unsigned int dst_x, + unsigned int dst_y, unsigned int dim_x, + unsigned int dim_y, unsigned int color) { - GraphicDevice *pGD = (GraphicDevice *)&mb862xx; + GraphicDevice *dev = &mb862xx; de_wait_slots (3); - DE_WR_REG (0x0480, color); + DE_WR_REG (GC_FC, color); DE_WR_FIFO (0x09410000); DE_WR_FIFO ((dst_y << 16) | dst_x); DE_WR_FIFO ((dim_y << 16) | dim_x); de_wait (); } -void video_hw_bitblt (unsigned int bpp, unsigned int src_x, unsigned int src_y, - unsigned int dst_x, unsigned int dst_y, unsigned int width, +void video_hw_bitblt (unsigned int bpp, unsigned int src_x, + unsigned int src_y, unsigned int dst_x, + unsigned int dst_y, unsigned int width, unsigned int height) { - GraphicDevice *pGD = (GraphicDevice *)&mb862xx; + GraphicDevice *dev = &mb862xx; unsigned int ctrl = 0x0d000000L; if (src_x >= dst_x && src_y >= dst_y) |