From 5ea5e14ba2919ce14bd7d8f5f6f202b04e502517 Mon Sep 17 00:00:00 2001 From: Robert Hodaszi Date: Mon, 23 May 2011 14:28:03 +0200 Subject: merge: merged changes from 2.6.28 Conflicts: gpio Special handling of PORT A gpios is lost. Some code has been ported but it must be fixed. Signed-off-by: Hector Palacios Signed-off-by: Robert Hodaszi --- drivers/char/adc-s3c2443.c | 3 +- drivers/input/touchscreen/s3c24xx_ts.c | 2 +- drivers/mmc/host/Kconfig | 11 + drivers/mmc/host/s3c-hsmmc.c | 44 +- drivers/mmc/host/s3cmci.c | 587 +++++-- drivers/mtd/nand/s3c2410.c | 427 ++--- drivers/net/Kconfig | 9 - drivers/net/Makefile | 1 - drivers/net/smsc9118/Makefile | 1 - drivers/net/smsc9118/smsc911x.c | 2711 -------------------------------- drivers/net/smsc9118/smsc911x.h | 393 ----- drivers/pcmcia/Kconfig | 7 + drivers/pcmcia/Makefile | 1 + drivers/serial/samsung.c | 32 +- drivers/spi/spi_s3c2443.c | 18 +- drivers/usb/gadget/Kconfig | 15 + drivers/usb/gadget/gadget_chips.h | 11 +- drivers/usb/gadget/s3c2443_udc.c | 16 +- drivers/usb/gadget/s3c2443_udc.h | 8 +- drivers/watchdog/s3c2410_wdt.c | 2 +- 20 files changed, 754 insertions(+), 3545 deletions(-) delete mode 100644 drivers/net/smsc9118/Makefile delete mode 100644 drivers/net/smsc9118/smsc911x.c delete mode 100644 drivers/net/smsc9118/smsc911x.h (limited to 'drivers') diff --git a/drivers/char/adc-s3c2443.c b/drivers/char/adc-s3c2443.c index 34de79e20045..1f41f18bca8b 100644 --- a/drivers/char/adc-s3c2443.c +++ b/drivers/char/adc-s3c2443.c @@ -29,9 +29,10 @@ #include #include #include +#include #include -#include +#include #define DRIVER_NAME "s3c2443-adc" #ifndef NUM_CHANNELS diff --git a/drivers/input/touchscreen/s3c24xx_ts.c b/drivers/input/touchscreen/s3c24xx_ts.c index dd6929551b29..58a851e7f105 100644 --- a/drivers/input/touchscreen/s3c24xx_ts.c +++ b/drivers/input/touchscreen/s3c24xx_ts.c @@ -65,7 +65,7 @@ #include #include -#include +#include #include diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 951f1fd2661f..d12d560e2a0b 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -418,6 +418,17 @@ config MMC_S3C_PIODMA endchoice +config HSMMC_S3C + tristate "Samsung S3C High Speed SD/MMC Card Interface support" + depends on ARCH_S3C2410 && MMC + help + This selects a driver for the High Speed MMC interface found in + Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs. + If you have a board based on one of those and a MMC/SD + slot, say Y or M here. + + If unsure, say N. + config MMC_SDRICOH_CS tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)" depends on EXPERIMENTAL && PCI && PCMCIA diff --git a/drivers/mmc/host/s3c-hsmmc.c b/drivers/mmc/host/s3c-hsmmc.c index 21986a2c72f7..e5d337159398 100644 --- a/drivers/mmc/host/s3c-hsmmc.c +++ b/drivers/mmc/host/s3c-hsmmc.c @@ -41,13 +41,15 @@ #include #include #include -#include +//#include #include #include #include #include #include +#include +#include #define printk_err(fmt, args...) printk(KERN_ERR "[ ERROR ] hsmmc: " fmt, ## args) @@ -192,7 +194,7 @@ static void s3c_hsmmc_activate_led(struct s3c_hsmmc_host *host) unsigned int ctrl; struct s3c_hsmmc_cfg *cfg = host->plat_data; - if (cfg->gpio_led == S3C2443_GPJ13) { + if (cfg->gpio_led == S3C2410_GPJ(13)) { ctrl = s3c_hsmmc_readl(S3C2410_HSMMC_HOSTCTL); ctrl &= ~S3C_HSMMC_CTRL_LED; s3c_hsmmc_writel(ctrl, S3C2410_HSMMC_HOSTCTL); @@ -210,7 +212,7 @@ static void s3c_hsmmc_deactivate_led(struct s3c_hsmmc_host *host) unsigned int ctrl; struct s3c_hsmmc_cfg *cfg = host->plat_data; - if (cfg->gpio_led == S3C2443_GPJ13) { + if (cfg->gpio_led == S3C2410_GPJ(13)) { ctrl = s3c_hsmmc_readl(S3C2410_HSMMC_HOSTCTL); ctrl |= S3C_HSMMC_CTRL_LED; s3c_hsmmc_writel(ctrl, S3C2410_HSMMC_HOSTCTL); @@ -996,33 +998,33 @@ static void s3c_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_ON: case MMC_POWER_UP: - s3c2410_gpio_cfgpin(S3C2443_GPL0, S3C2443_GPL0_SD0DAT0); + s3c2410_gpio_cfgpin(S3C2410_GPL(0), S3C2443_GPL0_SD0DAT0); if (cfg->host_caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) { - s3c2410_gpio_cfgpin(S3C2443_GPL1, S3C2443_GPL1_SD0DAT1); - s3c2410_gpio_cfgpin(S3C2443_GPL2, S3C2443_GPL2_SD0DAT2); - s3c2410_gpio_cfgpin(S3C2443_GPL3, S3C2443_GPL3_SD0DAT3); + s3c2410_gpio_cfgpin(S3C2410_GPL(1), S3C2443_GPL1_SD0DAT1); + s3c2410_gpio_cfgpin(S3C2410_GPL(2), S3C2443_GPL2_SD0DAT2); + s3c2410_gpio_cfgpin(S3C2410_GPL(3), S3C2443_GPL3_SD0DAT3); } if (cfg->host_caps & MMC_CAP_8_BIT_DATA) { - s3c2410_gpio_cfgpin(S3C2443_GPL4, S3C2443_GPL4_SD0DAT4); - s3c2410_gpio_cfgpin(S3C2443_GPL5, S3C2443_GPL5_SD0DAT5); - s3c2410_gpio_cfgpin(S3C2443_GPL6, S3C2443_GPL6_SD0DAT6); - s3c2410_gpio_cfgpin(S3C2443_GPL7, S3C2443_GPL7_SD0DAT7); + s3c2410_gpio_cfgpin(S3C2410_GPL(4), S3C2443_GPL4_SD0DAT4); + s3c2410_gpio_cfgpin(S3C2410_GPL(5), S3C2443_GPL5_SD0DAT5); + s3c2410_gpio_cfgpin(S3C2410_GPL(6), S3C2443_GPL6_SD0DAT6); + s3c2410_gpio_cfgpin(S3C2410_GPL(7), S3C2443_GPL7_SD0DAT7); } - s3c2410_gpio_cfgpin(S3C2443_GPL8, S3C2443_GPL8_SD0CMD); - s3c2410_gpio_cfgpin(S3C2443_GPL9, S3C2443_GPL9_SD0CLK); + s3c2410_gpio_cfgpin(S3C2410_GPL(8), S3C2443_GPL8_SD0CMD); + s3c2410_gpio_cfgpin(S3C2410_GPL(9), S3C2443_GPL9_SD0CLK); /* Check for the dedicated GPIOs of the HSMMC-controller */ - if (cfg->gpio_led == S3C2443_GPJ13) - s3c2410_gpio_cfgpin(S3C2443_GPJ13, S3C2440_GPJ13_SD0LED); + if (cfg->gpio_led == S3C2410_GPJ(13)) + s3c2410_gpio_cfgpin(S3C2410_GPJ(13), S3C2440_GPJ13_SD0LED); - if (cfg->gpio_detect == S3C2443_GPJ14) - s3c2410_gpio_cfgpin(S3C2443_GPJ14, S3C2440_GPJ14_SD0CD); + if (cfg->gpio_detect == S3C2410_GPJ(14)) + s3c2410_gpio_cfgpin(S3C2410_GPJ(14), S3C2440_GPJ14_SD0CD); - if (cfg->gpio_wprotect == S3C2443_GPJ15) - s3c2410_gpio_cfgpin(S3C2443_GPJ15, S3C2440_GPJ15_SD0WP); + if (cfg->gpio_wprotect == S3C2410_GPJ(15)) + s3c2410_gpio_cfgpin(S3C2410_GPJ(15), S3C2440_GPJ15_SD0WP); break; default: @@ -1072,7 +1074,7 @@ static int s3c_hsmmc_get_ro(struct mmc_host *mmc) unsigned int retval; /* Depending on the configured GPIO get the RO-value */ - if (cfg->gpio_wprotect == S3C2443_GPJ15) { + if (cfg->gpio_wprotect == S3C2410_GPJ(15)) { retval = s3c_hsmmc_readl(S3C2410_HSMMC_PRNSTS); retval &= S3C_HSMMC_WRITE_PROTECT; } else if (cfg->gpio_wprotect) { @@ -1323,7 +1325,7 @@ static int s3c_hsmmc_suspend(struct platform_device *pdev, pm_message_t state) clk_disable(host->clk[cnt]); } - retval = mmc_suspend_host(mmc, state); + retval = mmc_suspend_host(mmc); return retval; } diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 2e16e0a90a5e..f92f565e454e 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -3,9 +3,6 @@ * * Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel * - * Current driver maintained by Ben Dooks and Simtec Electronics - * Copyright (C) 2008 Simtec Electronics - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -22,11 +19,15 @@ #include #include #include - +#include #include +/* Use the old headers system */ #include #include +#include +#include +#include #include @@ -34,6 +35,22 @@ #define DRIVER_NAME "s3c-mci" +#define printk_err(fmt, args...) printk(KERN_ERR "[ ERROR ] s3c2443-sdi: " fmt, ## args) +#define printk_info(fmt, args...) printk(KERN_INFO "s3c2443-sdi: " fmt, ## args) +#define printk_dbg(fmt, args...) printk(KERN_DEBUG "s3c2443-sdi: " fmt, ## args) + +/* Enable/disable the debug messages */ +#if 0 +#define S3C2443_SDI_DEBUG +#endif + +#ifdef S3C2443_SDI_DEBUG +# define printk_debug(fmt, args...) printk(KERN_DEBUG "s3c2443-sdi: %s() " fmt, __FUNCTION__ , ## args) +#else +# define printk_debug(fmt, args...) +#endif + + enum dbg_channels { dbg_err = (1 << 0), dbg_debug = (1 << 1), @@ -46,9 +63,9 @@ enum dbg_channels { dbg_conf = (1 << 8), }; -static const int dbgmap_err = dbg_fail; +static const int dbgmap_err = dbg_err | dbg_fail; static const int dbgmap_info = dbg_info | dbg_conf; -static const int dbgmap_debug = dbg_err | dbg_debug; +static const int dbgmap_debug = dbg_debug; #define dbg(host, channels, args...) \ do { \ @@ -254,7 +271,7 @@ static void s3cmci_check_sdio_irq(struct s3cmci_host *host) } static inline int get_data_buffer(struct s3cmci_host *host, - u32 *bytes, u32 **pointer) + u32 *words, u32 **pointer) { struct scatterlist *sg; @@ -271,7 +288,7 @@ static inline int get_data_buffer(struct s3cmci_host *host, } sg = &host->mrq->data->sg[host->pio_sgptr]; - *bytes = sg->length; + *words = sg->length >> 2; *pointer = sg_virt(sg); host->pio_sgptr++; @@ -287,7 +304,7 @@ static inline u32 fifo_count(struct s3cmci_host *host) u32 fifostat = readl(host->base + S3C2410_SDIFSTA); fifostat &= S3C2410_SDIFSTA_COUNTMASK; - return fifostat; + return fifostat >> 2; } static inline u32 fifo_free(struct s3cmci_host *host) @@ -295,7 +312,7 @@ static inline u32 fifo_free(struct s3cmci_host *host) u32 fifostat = readl(host->base + S3C2410_SDIFSTA); fifostat &= S3C2410_SDIFSTA_COUNTMASK; - return 63 - fifostat; + return (63 - fifostat) >> 2; } /** @@ -306,10 +323,10 @@ static inline u32 fifo_free(struct s3cmci_host *host) * Enable the main IRQ if needed after it has been disabled. * * The IRQ can be one of the following states: - * - disabled during IDLE - * - disabled whilst processing data - * - enabled during transfer - * - enabled whilst awaiting SDIO interrupt detection + * - disabled during IDLE + * - disabled whilst processing data + * - enabled during transfer + * - enabled whilst awaiting SDIO interrupt detection */ static void s3cmci_enable_irq(struct s3cmci_host *host, bool more) { @@ -360,8 +377,6 @@ static void do_pio_read(struct s3cmci_host *host) { int res; u32 fifo; - u32 *ptr; - u32 fifo_words; void __iomem *from_ptr; /* write real prescaler to host, it might be set slow to fix */ @@ -392,35 +407,14 @@ static void do_pio_read(struct s3cmci_host *host) fifo, host->pio_bytes, readl(host->base + S3C2410_SDIDCNT)); - /* If we have reached the end of the block, we can - * read a word and get 1 to 3 bytes. If we in the - * middle of the block, we have to read full words, - * otherwise we will write garbage, so round down to - * an even multiple of 4. */ - if (fifo >= host->pio_bytes) + if (fifo > host->pio_bytes) fifo = host->pio_bytes; - else - fifo -= fifo & 3; host->pio_bytes -= fifo; host->pio_count += fifo; - fifo_words = fifo >> 2; - ptr = host->pio_ptr; - while (fifo_words--) - *ptr++ = readl(from_ptr); - host->pio_ptr = ptr; - - if (fifo & 3) { - u32 n = fifo & 3; - u32 data = readl(from_ptr); - u8 *p = (u8 *)host->pio_ptr; - - while (n--) { - *p++ = data; - data >>= 8; - } - } + while (fifo--) + *(host->pio_ptr++) = readl(from_ptr); } if (!host->pio_bytes) { @@ -444,7 +438,6 @@ static void do_pio_write(struct s3cmci_host *host) void __iomem *to_ptr; int res; u32 fifo; - u32 *ptr; to_ptr = host->base + host->sdidata; @@ -466,23 +459,14 @@ static void do_pio_write(struct s3cmci_host *host) } - /* If we have reached the end of the block, we have to - * write exactly the remaining number of bytes. If we - * in the middle of the block, we have to write full - * words, so round down to an even multiple of 4. */ - if (fifo >= host->pio_bytes) + if (fifo > host->pio_bytes) fifo = host->pio_bytes; - else - fifo -= fifo & 3; host->pio_bytes -= fifo; host->pio_count += fifo; - fifo = (fifo + 3) >> 2; - ptr = host->pio_ptr; while (fifo--) - writel(*ptr++, to_ptr); - host->pio_ptr = ptr; + writel(*(host->pio_ptr++), to_ptr); } enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF); @@ -492,6 +476,7 @@ static void pio_tasklet(unsigned long data) { struct s3cmci_host *host = (struct s3cmci_host *) data; + s3cmci_disable_irq(host, true); if (host->pio_active == XFER_WRITE) @@ -518,6 +503,17 @@ static void pio_tasklet(unsigned long data) s3cmci_enable_irq(host, true); } +/* The DMA-callback will call this function by errors or transfer completes */ +static void dma_tasklet(unsigned long data) +{ + struct s3cmci_host *host = (struct s3cmci_host *) data; + + if (host->complete_what == COMPLETION_FINALIZE) { + clear_imask(host); + finalize_request(host); + } +} + /* * ISR for SDI Interface IRQ * Communication between driver and ISR works as follows: @@ -573,6 +569,15 @@ static irqreturn_t s3cmci_irq(int irq, void *dev_id) mci_fsta = readl(host->base + S3C2410_SDIFSTA); mci_dclear = 0; + printk_debug("IRQ: cmd 0x%08x | dsta 0x%08x | imsk 0x%08x\n", + mci_csta, mci_dsta, mci_imsk); + + if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) { + printk_debug("SDIO IRQ detected\n"); + mmc_signal_sdio_irq(host->mmc); + writel(S3C2410_SDIDSTA_SDIOIRQDETECT, host->base + S3C2410_SDIDSTA); + } + if ((host->complete_what == COMPLETION_NONE) || (host->complete_what == COMPLETION_FINALIZE)) { host->status = "nothing to complete"; @@ -616,19 +621,22 @@ static irqreturn_t s3cmci_irq(int irq, void *dev_id) } if (mci_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) { - dbg(host, dbg_err, "CMDSTAT: error CMDTIMEOUT\n"); + dbg(host, dbg_debug, "CMDSTAT: error CMDTIMEOUT\n"); cmd->error = -ETIMEDOUT; host->status = "error: command timeout"; goto fail_transfer; } if (mci_csta & S3C2410_SDICMDSTAT_CMDSENT) { + + /* @FIXME: Move the write-command to a correct place! (Luis G.) */ + mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT; + writel(mci_cclear, host->base + S3C2410_SDICMDSTAT); + if (host->complete_what == COMPLETION_CMDSENT) { host->status = "ok: command sent"; goto close_transfer; } - - mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT; } if (mci_csta & S3C2410_SDICMDSTAT_CRCFAIL) { @@ -732,8 +740,22 @@ close_transfer: host->complete_what = COMPLETION_FINALIZE; clear_imask(host); - tasklet_schedule(&host->pio_tasklet); + /* + * If we have received an interrupt although we are waiting for the + * DMA-callback (cmd->data), then something went wrong with the last + * transfer. This happens when the card is removed before + * the card initialization was completed. + * (Luis Galdos) + */ + if (cmd->data && s3cmci_host_usedma(host) && !cmd->data->error && !cmd->error) { + host->dma_complete = 1; + cmd->error = cmd->data->error = -EILSEQ; + printk_debug("[SD] Waiting DMA (CMD %08x | DAT %08x)\n", + mci_csta, mci_dsta); + } + + tasklet_schedule(&host->pio_tasklet); goto irq_out; irq_out: @@ -750,13 +772,26 @@ irq_out: * ISR for the CardDetect Pin */ +static int s3cmci_card_present(struct mmc_host *mmc); + static irqreturn_t s3cmci_irq_cd(int irq, void *dev_id) { struct s3cmci_host *host = (struct s3cmci_host *)dev_id; - - dbg(host, dbg_irq, "card detect\n"); - - mmc_detect_change(host->mmc, msecs_to_jiffies(500)); + int val; + static int card_present; + + /* + * Get the current status of the GPIO for checking if the card state has + * really changed since the last interrupt. Otherwise it will generates + * more than one interrupt for the same state + * Luis Galdos + */ + val = s3cmci_card_present(host->mmc); + if (val != card_present) { + dbg(host, dbg_debug, "Card detect IRQ: %s\n", val ? "insert" : "remove"); + card_present = val; + mmc_detect_change(host->mmc, msecs_to_jiffies(500)); + } return IRQ_HANDLED; } @@ -781,30 +816,49 @@ static void s3cmci_dma_done_callback(struct s3c2410_dma_chan *dma_ch, spin_lock_irqsave(&host->complete_lock, iflags); if (result != S3C2410_RES_OK) { - dbg(host, dbg_fail, "DMA FAILED: csta=0x%08x dsta=0x%08x " - "fsta=0x%08x dcnt:0x%08x result:0x%08x toGo:%u\n", - mci_csta, mci_dsta, mci_fsta, - mci_dcnt, result, host->dmatogo); + struct mmc_request *mrq = host->mrq; + + if (mrq) { + struct mmc_command *cmd; + + cmd = mrq->cmd; + dbg(host, dbg_fail, "DMA FAILED: CMD%i csta=0x%08x dsta=0x%08x " + "fsta=0x%08x dcnt:0x%08x result:%i toGo:%u\n", + cmd->opcode, mci_csta, mci_dsta, mci_fsta, + mci_dcnt, result, host->dmatogo); + } else + dbg(host, dbg_fail, "DMA FAILED: csta=0x%08x dsta=0x%08x " + "fsta=0x%08x dcnt:0x%08x result:0x%08x toGo:%u\n", + mci_csta, mci_dsta, mci_fsta, + mci_dcnt, result, host->dmatogo); goto fail_request; } host->dmatogo--; if (host->dmatogo) { - dbg(host, dbg_dma, "DMA DONE Size:%i DSTA:[%08x] " - "DCNT:[%08x] toGo:%u\n", - size, mci_dsta, mci_dcnt, host->dmatogo); + printk_debug("DMA DONE Size:%i DSTA:[%08x] " + "DCNT:[%08x] toGo:%u\n", + size, mci_dsta, mci_dcnt, host->dmatogo); - goto out; + if (mci_dsta & S3C2410_SDIDSTA_XFERFINISH) { + printk_err("SDI has no more data, but DMA waits for more?\n"); + goto fail_request; + } + + spin_unlock_irqrestore(&host->complete_lock, iflags); + return; } - dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n", - size, mci_dsta, mci_dcnt); + printk_debug("DMA ENDE Size:%i DSTA:[%08x] DCNT:[%08x]\n", + size, mci_dsta, mci_dcnt); host->dma_complete = 1; host->complete_what = COMPLETION_FINALIZE; out: + /* @FIXME: Check the performance modification through this delay */ + udelay(10); tasklet_schedule(&host->pio_tasklet); spin_unlock_irqrestore(&host->complete_lock, iflags); return; @@ -815,6 +869,7 @@ fail_request: clear_imask(host); goto out; + } static void finalize_request(struct s3cmci_host *host) @@ -823,19 +878,24 @@ static void finalize_request(struct s3cmci_host *host) struct mmc_command *cmd; int debug_as_failure = 0; - if (host->complete_what != COMPLETION_FINALIZE) - return; + spin_lock(&host->complete_lock); + + if (host->complete_what != COMPLETION_FINALIZE) { + printk_debug("Nothing to complete!\n"); + goto exit_unlock; + } + + if (!mrq) { + printk_err("Empty MMC request found!\n"); + goto exit_unlock; + } - if (!mrq) - return; cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd; - if (cmd->data && (cmd->error == 0) && - (cmd->data->error == 0)) { + if (cmd->data && (cmd->error == 0) && (cmd->data->error == 0)) { if (s3cmci_host_usedma(host) && (!host->dma_complete)) { - dbg(host, dbg_dma, "DMA Missing (%d)!\n", - host->dma_complete); - return; + printk_err("DMA complete missing (%i)\n", host->dma_complete); + goto exit_unlock; } } @@ -857,8 +917,8 @@ static void finalize_request(struct s3cmci_host *host) /* Cleanup controller */ writel(0, host->base + S3C2410_SDICMDARG); - writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON); writel(0, host->base + S3C2410_SDICMDCON); + writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON); clear_imask(host); if (cmd->data && cmd->error) @@ -867,7 +927,7 @@ static void finalize_request(struct s3cmci_host *host) if (cmd->data && cmd->data->stop && (!host->cmd_is_stop)) { host->cmd_is_stop = 1; s3cmci_send_request(host->mmc); - return; + goto exit_unlock; } /* If we have no data transfer we are finished here */ @@ -910,13 +970,17 @@ request_done: s3cmci_check_sdio_irq(host); mmc_request_done(host->mmc, mrq); + + exit_unlock: + spin_unlock(&host->complete_lock); + } static void s3cmci_dma_setup(struct s3cmci_host *host, enum s3c2410_dmasrc source) { static enum s3c2410_dmasrc last_source = -1; - static int setup_ok; + static int setup_ok = 0; if (last_source == source) return; @@ -927,10 +991,11 @@ static void s3cmci_dma_setup(struct s3cmci_host *host, host->mem->start + host->sdidata); if (!setup_ok) { + printk_debug("Setting up the DMA channel!\n"); s3c2410_dma_config(host->dma, 4); s3c2410_dma_set_buffdone_fn(host->dma, s3cmci_dma_done_callback); - s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART); + s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); setup_ok = 1; } } @@ -982,10 +1047,11 @@ static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data) /* We cannot deal with unaligned blocks with more than * one block being transfered. */ - if (data->blocks > 1) { - pr_warning("%s: can't do non-word sized block transfers (blksz %d)\n", __func__, data->blksz); + if (data->blocks > 1) return -EINVAL; - } + + /* No support yet for non-word block transfers. */ + return -EINVAL; } while (readl(host->base + S3C2410_SDIDSTA) & @@ -1032,12 +1098,15 @@ static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data) writel(dcon, host->base + S3C2410_SDIDCON); /* write BSIZE register */ - writel(data->blksz, host->base + S3C2410_SDIBSIZE); /* add to IMASK register */ imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC | - S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH; + S3C2410_SDIIMSK_DATATIMEOUT; + + /* By DMA-support we will use the DMA-callback for the transfer-complete */ + if (!s3cmci_host_usedma(host)) + imsk |= S3C2410_SDIIMSK_DATAFINISH; enable_imask(host, imsk); @@ -1084,27 +1153,33 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) { int dma_len, i; int rw = data->flags & MMC_DATA_WRITE; + int retval; BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR); - s3cmci_dma_setup(host, rw ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW); + printk_debug("New DMA transfer | %i Blks | %i Blksz\n", + data->blocks, data->blksz); + s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); + s3cmci_dma_setup(host, rw ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW); dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - if (dma_len == 0) - return -ENOMEM; + if (dma_len == 0) { + printk_err("dma_map_sg failed, no memory available?\n"); + retval = -ENOMEM; + goto exit_all; + } - host->dma_complete = 0; host->dmatogo = dma_len; for (i = 0; i < dma_len; i++) { int res; - dbg(host, dbg_dma, "enqueue %i: %08x@%u\n", i, - sg_dma_address(&data->sg[i]), - sg_dma_len(&data->sg[i])); + printk_debug("Enqueue %i @ 0x%08x | %u bytes\n", i, + sg_dma_address(&data->sg[i]), + sg_dma_len(&data->sg[i])); res = s3c2410_dma_enqueue(host->dma, host, sg_dma_address(&data->sg[i]), @@ -1112,13 +1187,31 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data) if (res) { s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH); - return -EBUSY; + printk_err("Couldn't enqueue a DMA-buffer\n"); + retval = -EBUSY; + goto exit_all; } } + /* + * Disable the data counter interrupt, then the DMA-callback will be + * responsible for finalizing the request + */ + disable_imask(host, S3C2410_SDIIMSK_DATAFINISH | + S3C2410_SDIIMSK_RXFIFOHALF | + S3C2410_SDIIMSK_RXFIFOFULL | + S3C2410_SDIIMSK_RXFIFOLAST | + S3C2410_SDIIMSK_TXFIFOEMPTY | + S3C2410_SDIIMSK_TXFIFOHALF); + + host->dma_complete = 0; s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_START); - return 0; + retval = 0; + + exit_all: + + return retval; } static void s3cmci_send_request(struct mmc_host *mmc) @@ -1130,6 +1223,10 @@ static void s3cmci_send_request(struct mmc_host *mmc) host->ccnt++; prepare_dbgmsg(host, cmd, host->cmd_is_stop); + /* @XXX: Sending the switch command with data leads to a DMA-failure, why? */ + if (cmd->opcode == MMC_SWITCH && cmd->data) + udelay(200); + /* Clear command, data and fifo status registers Fifo clear only necessary on 2440, but doesn't hurt on 2410 */ @@ -1140,6 +1237,11 @@ static void s3cmci_send_request(struct mmc_host *mmc) if (cmd->data) { int res = s3cmci_setup_data(host, cmd->data); + printk_debug("CMD%u: %s transfer | %i blks | %u blksz\n", + cmd->opcode, + (cmd->data->flags & MMC_DATA_READ) ? "RX" : "TX", + cmd->data->blocks, cmd->data->blksz); + host->dcnt++; if (res) { @@ -1170,7 +1272,24 @@ static void s3cmci_send_request(struct mmc_host *mmc) s3cmci_send_command(host, cmd); /* Enable Interrupt */ - s3cmci_enable_irq(host, true); + if (!s3cmci_host_usedma(host)) + s3cmci_enable_irq(host, true); + + /* + * If the host supports DMA, then disable the data finish interrupts and + * the FIFO-interrupts, then the DMA-controller will handle the data + * transfer and will finish the transfer if no errors ocurrs + * @XXX: This is probably not the correct place for this operation + * (Luis Galdos) + */ + if (cmd->data && s3cmci_host_usedma(host)) + disable_imask(host, S3C2410_SDIIMSK_DATAFINISH | + S3C2410_SDIIMSK_RXFIFOHALF | + S3C2410_SDIIMSK_RXFIFOFULL | + S3C2410_SDIIMSK_RXFIFOLAST | + S3C2410_SDIIMSK_TXFIFOEMPTY | + S3C2410_SDIIMSK_TXFIFOHALF); + } static int s3cmci_card_present(struct mmc_host *mmc) @@ -1195,40 +1314,18 @@ static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq) host->mrq = mrq; if (s3cmci_card_present(mmc) == 0) { - dbg(host, dbg_err, "%s: no medium present\n", __func__); + dbg(host, dbg_debug, "%s: no medium present\n", __func__); host->mrq->cmd->error = -ENOMEDIUM; mmc_request_done(mmc, mrq); } else s3cmci_send_request(mmc); } -static void s3cmci_set_clk(struct s3cmci_host *host, struct mmc_ios *ios) -{ - u32 mci_psc; - - /* Set clock */ - for (mci_psc = 0; mci_psc < 255; mci_psc++) { - host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1)); - - if (host->real_rate <= ios->clock) - break; - } - - if (mci_psc > 255) - mci_psc = 255; - - host->prescaler = mci_psc; - writel(host->prescaler, host->base + S3C2410_SDIPRE); - - /* If requested clock is 0, real_rate will be 0, too */ - if (ios->clock == 0) - host->real_rate = 0; -} - static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct s3cmci_host *host = mmc_priv(mmc); - u32 mci_con; + u32 mci_psc, mci_con; + int waitclk; /* Set the power state */ @@ -1237,13 +1334,6 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_ON: case MMC_POWER_UP: - s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK); - s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD); - s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0); - s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1); - s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2); - s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3); - if (host->pdata->set_power) host->pdata->set_power(ios->power_mode, ios->vdd); @@ -1254,8 +1344,6 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) case MMC_POWER_OFF: default: - gpio_direction_output(S3C2410_GPE(5), 0); - if (host->is2440) mci_con |= S3C2440_SDICON_SDRESET; @@ -1265,8 +1353,6 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) break; } - s3cmci_set_clk(host, ios); - /* Set CLOCK_ENABLE */ if (ios->clock) mci_con |= S3C2410_SDICON_CLOCKTYPE; @@ -1275,12 +1361,47 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) writel(mci_con, host->base + S3C2410_SDICON); + + /* Set clock */ + for (mci_psc = 0; mci_psc < 255; mci_psc++) { + host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1)); + + if (host->real_rate <= ios->clock) + break; + } + + if (mci_psc > 255) + mci_psc = 255; + + + /* If requested clock is 0, real_rate will be 0, too */ + if (ios->clock == 0) + host->real_rate = 0; + + host->prescaler = mci_psc; + writel(host->prescaler, host->base + S3C2410_SDIPRE); + + /* + * According to the data sheet first configure the register SDICON and + * wait at least 74 SDCLK before initializing the SD card. + * (Luis Galdos) + */ + waitclk = 1; + if (host->real_rate) + waitclk = 100 * (1000000 / host->real_rate); + + if (waitclk > 1000) + mdelay(waitclk / 1000); + else + udelay(waitclk); + + if ((ios->power_mode == MMC_POWER_ON) || (ios->power_mode == MMC_POWER_UP)) { - dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n", + dbg(host, dbg_debug, "running at %lukHz (requested: %ukHz).\n", host->real_rate/1000, ios->clock/1000); } else { - dbg(host, dbg_conf, "powered down.\n"); + dbg(host, dbg_debug, "powered down.\n"); } host->bus_width = ios->bus_width; @@ -1350,20 +1471,20 @@ static void s3cmci_enable_sdio_irq(struct mmc_host *mmc, int enable) } static struct mmc_host_ops s3cmci_ops = { - .request = s3cmci_request, - .set_ios = s3cmci_set_ios, - .get_ro = s3cmci_get_ro, - .get_cd = s3cmci_card_present, + .request = s3cmci_request, + .set_ios = s3cmci_set_ios, + .get_ro = s3cmci_get_ro, .enable_sdio_irq = s3cmci_enable_sdio_irq, }; static struct s3c24xx_mci_pdata s3cmci_def_pdata = { /* This is currently here to avoid a number of if (host->pdata) * checks. Any zero fields to ensure reasonable defaults are picked. */ - .no_wprotect = 1, - .no_detect = 1, + .no_wprotect = 1, + .no_detect = 1, }; +#if 0 #ifdef CONFIG_CPU_FREQ static int s3cmci_cpufreq_transition(struct notifier_block *nb, @@ -1418,7 +1539,7 @@ static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host) { } #endif - +#endif #ifdef CONFIG_DEBUG_FS @@ -1486,7 +1607,7 @@ static int s3cmci_regs_show(struct seq_file *seq, void *v) for (; rptr->name; rptr++) seq_printf(seq, "SDI%s\t=0x%08x\n", rptr->name, - readl(host->base + rptr->addr)); + readl(host->base + rptr->addr)); seq_printf(seq, "SDIIMSK\t=0x%08x\n", readl(host->base + host->sdiimsk)); @@ -1524,8 +1645,8 @@ static void s3cmci_debugfs_attach(struct s3cmci_host *host) dev_err(dev, "failed to create debug state file\n"); host->debug_regs = debugfs_create_file("regs", 0444, - host->debug_root, host, - &s3cmci_fops_regs); + host->debug_root, host, + &s3cmci_fops_regs); if (IS_ERR(host->debug_regs)) dev_err(dev, "failed to create debug regs file\n"); @@ -1583,9 +1704,6 @@ static int __devinit s3cmci_probe(struct platform_device *pdev) host->pdata = &s3cmci_def_pdata; } - spin_lock_init(&host->complete_lock); - tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host); - if (is2440) { host->sdiimsk = S3C2440_SDIIMSK; host->sdidata = S3C2440_SDIDATA; @@ -1600,9 +1718,17 @@ static int __devinit s3cmci_probe(struct platform_device *pdev) host->pio_active = XFER_NONE; #ifdef CONFIG_MMC_S3C_PIODMA - host->dodma = host->pdata->dma; + host->dodma = host->pdata->use_dma; #endif + spin_lock_init(&host->complete_lock); + + /* Depending on the DMA-support use different tasklet-functions */ + if (!s3cmci_host_usedma(host)) + tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host); + else + tasklet_init(&host->pio_tasklet, dma_tasklet, (unsigned long) host); + host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!host->mem) { dev_err(&pdev->dev, @@ -1723,7 +1849,7 @@ static int __devinit s3cmci_probe(struct platform_device *pdev) #ifdef CONFIG_MMC_S3C_HW_SDIO_IRQ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; #else - mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->caps = MMC_CAP_4_BIT_DATA; #endif mmc->f_min = host->clk_rate / (host->clk_div * 256); mmc->f_max = host->clk_rate / host->clk_div; @@ -1744,29 +1870,51 @@ static int __devinit s3cmci_probe(struct platform_device *pdev) (host->is2440?"2440":""), host->base, host->irq, host->irq_cd, host->dma); +#if 0 ret = s3cmci_cpufreq_register(host); if (ret) { dev_err(&pdev->dev, "failed to register cpufreq\n"); goto free_dmabuf; } +#endif ret = mmc_add_host(mmc); if (ret) { dev_err(&pdev->dev, "failed to add mmc host.\n"); +#if 0 goto free_cpufreq; +#else + goto free_dmabuf; +#endif } + /* @FIXME: Get the GPIO-list from the platform-data */ + s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK); + s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD); + s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0); + s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1); + s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2); + s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3); + s3cmci_debugfs_attach(host); platform_set_drvdata(pdev, mmc); dev_info(&pdev->dev, "%s - using %s, %s SDIO IRQ\n", mmc_hostname(mmc), - s3cmci_host_usedma(host) ? "dma" : "pio", - mmc->caps & MMC_CAP_SDIO_IRQ ? "hw" : "sw"); + s3cmci_host_usedma(host) ? "dma" : "pio", + mmc->caps & MMC_CAP_SDIO_IRQ ? "hw" : "sw"); + + /* Enable the wakeup for this device (Luis Galdos) */ + device_init_wakeup(&pdev->dev, 1); + device_set_wakeup_enable(&pdev->dev, 0); + + s3cmci_enable_irq(host, true); return 0; +#if 0 free_cpufreq: s3cmci_cpufreq_deregister(host); +#endif free_dmabuf: clk_disable(host->clk); @@ -1819,11 +1967,29 @@ static void s3cmci_shutdown(struct platform_device *pdev) free_irq(host->irq_cd, host); s3cmci_debugfs_remove(host); +#if 0 s3cmci_cpufreq_deregister(host); +#endif mmc_remove_host(mmc); clk_disable(host->clk); } +/* + * Don't remove the MMC-host when going to shutdown the system. This can lead to some + * failures when the host has mounted a card with our root file system. + * (Luis Galdos) + */ +static void s3cmci_2440_shutdown(struct platform_device *pdev) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + struct s3cmci_host *host = mmc_priv(mmc); + + if (host->irq_cd >= 0) + free_irq(host->irq_cd, host); + + clk_disable(host->clk); +} + static int __devexit s3cmci_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); @@ -1837,6 +2003,7 @@ static int __devexit s3cmci_remove(struct platform_device *pdev) tasklet_disable(&host->pio_tasklet); + /* Free the DMA-channel */ if (s3cmci_host_usedma(host)) s3c2410_dma_free(host->dma, &s3cmci_dma_client); @@ -1851,7 +2018,6 @@ static int __devexit s3cmci_remove(struct platform_device *pdev) for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) gpio_free(i); - iounmap(host->base); release_mem_region(host->mem->start, resource_size(host->mem)); @@ -1861,14 +2027,14 @@ static int __devexit s3cmci_remove(struct platform_device *pdev) static struct platform_device_id s3cmci_driver_ids[] = { { - .name = "s3c2410-sdi", - .driver_data = 0, + .name = "s3c2410-sdi", + .driver_data = 0, }, { - .name = "s3c2412-sdi", - .driver_data = 1, + .name = "s3c2412-sdi", + .driver_data = 1, }, { - .name = "s3c2440-sdi", - .driver_data = 1, + .name = "s3c2440-sdi", + .driver_data = 1, }, { } }; @@ -1880,21 +2046,97 @@ MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids); static int s3cmci_suspend(struct device *dev) { - struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev)); + int retval; + struct mmc_host *mmc; + struct s3cmci_host *host; - return mmc_suspend_host(mmc); + mmc = platform_get_drvdata(to_platform_device(dev)); + host = mmc_priv(mmc); + + retval = mmc_suspend_host(mmc); + if (retval) + goto exit_suspend; + + /* Check if the wakeup is enabled. IN that case configure it as ext wakeup */ + if (device_may_wakeup(dev)) { + struct s3c24xx_mci_pdata *pdata; + unsigned long detect; + + pdata = host->pdata; + + retval = enable_irq_wake(host->irq_cd); + if (retval) { + dev_err(dev, "Couldn't enable wake IRQ %i\n", + host->irq_cd); + goto exit_suspend; + } + + /* + * Reconfigure the card for generating the wakeup when a new + * card is plugged into the slot + */ + detect = (pdata->detect_invert) ? (IRQF_TRIGGER_RISING) : + (IRQF_TRIGGER_FALLING); + set_irq_type(host->irq_cd, detect); + } + + writel(S3C2440_SDICON_SDRESET | S3C2410_SDIDCON_STOP, + host->base + S3C2410_SDICON); + + clk_disable(host->clk); +exit_suspend: + return retval; } static int s3cmci_resume(struct device *dev) { - struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev)); + struct s3cmci_host *host; + struct mmc_host *mmc; + int retval; + + mmc = platform_get_drvdata(to_platform_device(dev)); + host = mmc_priv(mmc); - return mmc_resume_host(mmc); + if (device_may_wakeup(dev)) { + retval = disable_irq_wake(host->irq_cd); + if (retval) { + dev_err(dev, "Couldn't disable wake IRQ %i\n", + host->irq_cd); + goto exit_resume; + } + + set_irq_type(host->irq_cd, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING); + } + + clk_enable(host->clk); + + /* @FIXME: Why do we need to free que DMA-channel? */ + s3c2410_dma_free(host->dma, &s3cmci_dma_client); + s3c2410_dma_request(host->dma, &s3cmci_dma_client, NULL); + + /* + * By unsafe resumes we MUST check the card state at this point, then the + * higher MMC-layer is probably transferring some kind of data to the + * block device that doesn't exist any more. + */ +#if defined(CONFIG_MMC_UNSAFE_RESUME) + if (s3cmci_card_present(mmc)) + retval = mmc_resume_host(mmc); + else { + retval = 0; + mmc_detect_change(mmc, msecs_to_jiffies(500)); + } +#else + retval = mmc_resume_host(mmc); +#endif /* CONFIG_MMC_UNSAFE_RESUME */ + +exit_resume: + return retval; } static const struct dev_pm_ops s3cmci_pm = { - .suspend = s3cmci_suspend, - .resume = s3cmci_resume, + .suspend = s3cmci_suspend, + .resume = s3cmci_resume, }; #define s3cmci_pm_ops &s3cmci_pm @@ -1904,17 +2146,18 @@ static const struct dev_pm_ops s3cmci_pm = { static struct platform_driver s3cmci_driver = { - .driver = { - .name = "s3c-sdi", - .owner = THIS_MODULE, - .pm = s3cmci_pm_ops, + .driver = { + .name = "s3c-sdi", + .owner = THIS_MODULE, + .pm = s3cmci_pm_ops, }, .id_table = s3cmci_driver_ids, .probe = s3cmci_probe, .remove = __devexit_p(s3cmci_remove), - .shutdown = s3cmci_shutdown, + .shutdown = s3cmci_2440_shutdown, }; + static int __init s3cmci_init(void) { return platform_driver_register(&s3cmci_driver); @@ -1930,4 +2173,4 @@ module_exit(s3cmci_exit); MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver"); MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Thomas Kleffel , Ben Dooks "); +MODULE_AUTHOR("Thomas Kleffel "); diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 239aadfd01b0..55906ffbc561 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -1,10 +1,26 @@ /* linux/drivers/mtd/nand/s3c2410.c * - * Copyright © 2004-2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ + * Copyright (c) 2004,2005 Simtec Electronics + * http://www.simtec.co.uk/products/SWLINUX/ * Ben Dooks * - * Samsung S3C2410/S3C2440/S3C2412 NAND driver + * Samsung S3C2410/S3C240 NAND driver + * + * Changelog: + * 21-Sep-2004 BJD Initial version + * 23-Sep-2004 BJD Multiple device support + * 28-Sep-2004 BJD Fixed ECC placement for Hardware mode + * 12-Oct-2004 BJD Fixed errors in use of platform data + * 18-Feb-2005 BJD Fix sparse errors + * 14-Mar-2005 BJD Applied tglx's code reduction patch + * 02-May-2005 BJD Fixed s3c2440 support + * 02-May-2005 BJD Reduced hwcontrol decode + * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug + * 08-Jul-2005 BJD Fix OOPS when no platform data supplied + * 20-Oct-2005 BJD Fix timing calculation bug + * 14-Jan-2006 BJD Allow clock to be stopped when idle + * + * $Id: s3c2410.c,v 1.23 2006/04/01 18:06:29 bjd Exp $ * * 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 @@ -19,11 +35,7 @@ * 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 -*/ - -#ifdef CONFIG_MTD_NAND_S3C2410_DEBUG -#define DEBUG -#endif + */ #include #include @@ -36,7 +48,6 @@ #include #include #include -#include #include #include @@ -48,6 +59,13 @@ #include #include +/* Name of the kernel boot parameter with the partitions table */ +#define PARTITON_PARAMETER_NAME "onboard_boot" + +#if defined(CONFIG_MTD_NAND_S3C2410_DEBUG) && !defined(DEBUG) +#define DEBUG +#endif + #ifdef CONFIG_MTD_NAND_S3C2410_HWECC static int hardware_ecc = 1; #else @@ -61,13 +79,35 @@ static const int clock_stop = 0; #endif -/* new oob placement block for use with hardware ecc generation +/* + * These are the values that we are using in the U-Boot too. + * Luis Galdos */ static struct nand_ecclayout nand_hw_eccoob = { - .eccbytes = 3, - .eccpos = {0, 1, 2}, - .oobfree = {{8, 8}} + .eccbytes = 4, + .eccpos = { 40, 41, 42, 43 }, + .oobfree = { + { + .offset = 2, + .length = 38 + } + } +}; + +/* + * Nand flash oob definition for SLC 512b page size by jsgood + * IMPORTANT: These values are coming from the U-Boot + */ +static struct nand_ecclayout nand_hw_eccoob_16 = { + .eccbytes = 6, + .eccpos = { 0, 1, 2, 3, 6, 7 }, + .oobfree = { + { + .offset = 8, + .length = 8 + } + } }; /* controller and mtd information */ @@ -110,7 +150,6 @@ enum s3c_cpu_type { * @sel_bit: The bit in @sel_reg to select the NAND chip. * @mtd_count: The number of MTDs created from this controller. * @save_sel: The contents of @sel_reg to be saved over suspend. - * @clk_rate: The clock rate from @clk. * @cpu_type: The exact type of this controller. */ struct s3c2410_nand_info { @@ -128,13 +167,9 @@ struct s3c2410_nand_info { int sel_bit; int mtd_count; unsigned long save_sel; - unsigned long clk_rate; enum s3c_cpu_type cpu_type; -#ifdef CONFIG_CPU_FREQ - struct notifier_block freq_transition; -#endif }; /* conversion functions */ @@ -200,25 +235,24 @@ static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max) /* controller setup */ /** - * s3c2410_nand_setrate - setup controller timing information. - * @info: The controller instance. + * s3c2410_nand_inithw - basic hardware initialisation + * @info: The hardware state. + * @pdev: Platform device * - * Given the information supplied by the platform, calculate and set - * the necessary timing registers in the hardware to generate the - * necessary timing cycles to the hardware. - */ -static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) + * Do the basic initialisation of the hardware,setup the hardware + * access speeds and set the controller to be enabled. +*/ +static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, + struct platform_device *pdev) { - struct s3c2410_platform_nand *plat = info->platform; + struct s3c2410_platform_nand *plat = to_nand_plat(pdev); + unsigned long clkrate = clk_get_rate(info->clk); int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4; int tacls, twrph0, twrph1; - unsigned long clkrate = clk_get_rate(info->clk); - unsigned long uninitialized_var(set), cfg, uninitialized_var(mask); - unsigned long flags; + unsigned long cfg = 0; /* calculate the timing information for the controller */ - info->clk_rate = clkrate; clkrate /= 1000; /* turn clock into kHz for ease of use */ if (plat != NULL) { @@ -240,73 +274,37 @@ static int s3c2410_nand_setrate(struct s3c2410_nand_info *info) dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n", tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate)); + /* + * First get the current value of the configuration register, otherwise + * some chip-information that is coming from the bootloader will be + * gone (e.g. the page size, which is required for the HWECC) + * Luis Galdos + */ + + cfg = readl(info->regs + S3C2410_NFCONF); + switch (info->cpu_type) { case TYPE_S3C2410: - mask = (S3C2410_NFCONF_TACLS(3) | - S3C2410_NFCONF_TWRPH0(7) | - S3C2410_NFCONF_TWRPH1(7)); - set = S3C2410_NFCONF_EN; - set |= S3C2410_NFCONF_TACLS(tacls - 1); - set |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); - set |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); + cfg |= S3C2410_NFCONF_EN; + cfg |= S3C2410_NFCONF_TACLS(tacls - 1); + cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); + cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); break; case TYPE_S3C2440: case TYPE_S3C2412: - mask = (S3C2440_NFCONF_TACLS(tacls_max - 1) | - S3C2440_NFCONF_TWRPH0(7) | - S3C2440_NFCONF_TWRPH1(7)); - - set = S3C2440_NFCONF_TACLS(tacls - 1); - set |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); - set |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); - break; - - default: - BUG(); - } - - local_irq_save(flags); - - cfg = readl(info->regs + S3C2410_NFCONF); - cfg &= ~mask; - cfg |= set; - writel(cfg, info->regs + S3C2410_NFCONF); - - local_irq_restore(flags); - - dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); - - return 0; -} - -/** - * s3c2410_nand_inithw - basic hardware initialisation - * @info: The hardware state. - * - * Do the basic initialisation of the hardware, using s3c2410_nand_setrate() - * to setup the hardware access speeds and set the controller to be enabled. -*/ -static int s3c2410_nand_inithw(struct s3c2410_nand_info *info) -{ - int ret; - - ret = s3c2410_nand_setrate(info); - if (ret < 0) - return ret; - - switch (info->cpu_type) { - case TYPE_S3C2410: - default: - break; + cfg |= S3C2440_NFCONF_TACLS(tacls - 1); + cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1); + cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1); - case TYPE_S3C2440: - case TYPE_S3C2412: /* enable the controller and de-assert nFCE */ writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT); } + dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg); + + writel(cfg, info->regs + S3C2410_NFCONF); return 0; } @@ -424,74 +422,72 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - unsigned int diff0, diff1, diff2; - unsigned int bit, byte; - - pr_debug("%s(%p,%p,%p,%p)\n", __func__, mtd, dat, read_ecc, calc_ecc); - - diff0 = read_ecc[0] ^ calc_ecc[0]; - diff1 = read_ecc[1] ^ calc_ecc[1]; - diff2 = read_ecc[2] ^ calc_ecc[2]; - - pr_debug("%s: rd %02x%02x%02x calc %02x%02x%02x diff %02x%02x%02x\n", - __func__, - read_ecc[0], read_ecc[1], read_ecc[2], - calc_ecc[0], calc_ecc[1], calc_ecc[2], - diff0, diff1, diff2); + unsigned long nfmeccdata0, nfmeccdata1; + unsigned long nfestat0; + unsigned char err_type; + int retval; + unsigned int offset; + unsigned char wrong_value, corr_value; + struct s3c2410_nand_mtd *nmtd = s3c2410_nand_mtd_toours(mtd); + struct nand_chip *chip = &nmtd->chip; - if (diff0 == 0 && diff1 == 0 && diff2 == 0) - return 0; /* ECC is ok */ + pr_debug("%s: read %02x%02x%02x%02x calc %02x%02x%02x%02x\n", __func__, + read_ecc[0], read_ecc[1], read_ecc[2], read_ecc[3], + calc_ecc[0], calc_ecc[1], calc_ecc[2], calc_ecc[3]); /* sometimes people do not think about using the ECC, so check * to see if we have an 0xff,0xff,0xff read ECC and then ignore * the error, on the assumption that this is an un-eccd page. */ if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff - && info->platform->ignore_unset_ecc) + && read_ecc[3] == 0xff && info->platform->ignore_unset_ecc) { + pr_debug("Ignoring the HWECC calculation?\n"); return 0; - - /* Can we correct this ECC (ie, one row and column change). - * Note, this is similar to the 256 error code on smartmedia */ - - if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 && - ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 && - ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) { - /* calculate the bit position of the error */ - - bit = ((diff2 >> 3) & 1) | - ((diff2 >> 4) & 2) | - ((diff2 >> 5) & 4); - - /* calculate the byte position of the error */ - - byte = ((diff2 << 7) & 0x100) | - ((diff1 << 0) & 0x80) | - ((diff1 << 1) & 0x40) | - ((diff1 << 2) & 0x20) | - ((diff1 << 3) & 0x10) | - ((diff0 >> 4) & 0x08) | - ((diff0 >> 3) & 0x04) | - ((diff0 >> 2) & 0x02) | - ((diff0 >> 1) & 0x01); - - dev_dbg(info->device, "correcting error bit %d, byte %d\n", - bit, byte); - - dat[byte] ^= (1 << bit); - return 1; } - /* if there is only one bit difference in the ECC, then - * one of only a row or column parity has changed, which - * means the error is most probably in the ECC itself */ - - diff0 |= (diff1 << 8); - diff0 |= (diff2 << 16); + /* + * If the chip has a small page then set the fourth byte to 0xff, so that + * we can use the NAND-controller to check if the ECC is correct or not. + * Please note that this "workaround" is coming from the U-Boot, which has + * an ECC-layout with only three ECC-bytes (but why?). + * (Luis Galdos) + */ + if (chip->page_shift <= 10) { + pr_debug("Setting the fourth byte to 0xff\n"); + read_ecc[3] = 0xff; + } - if ((diff0 & ~(1<regs + S3C2440_NFECCD0); + writel(nfmeccdata1, info->regs + S3C2440_NFECCD1); + nfestat0 = readl(info->regs + S3C2412_NFMECC_ERR0); + err_type = nfestat0 & 0x3; + + switch (err_type) { + case 0: + retval = 0; + break; + case 1: + offset = (nfestat0 >> 7) & 0x7ff; + wrong_value = dat[offset]; + corr_value = wrong_value ^ (1 << ((nfestat0 >> 4) & 0x7)); + printk(KERN_DEBUG "[NAND BitErr]: 1 bit error detected at page byte %u. Correcting from 0x%02x to 0x%02x\n", + offset, wrong_value, corr_value); + dat[offset] = corr_value; + retval = 1; + break; + default: + printk(KERN_ERR "[NAND BitErr]: More than 1 bit error detected. Uncorrectable error.\n"); + retval = -1; + break; + } - return -1; + return retval; } /* ECC functions @@ -515,8 +511,21 @@ static void s3c2412_nand_enable_hwecc(struct mtd_info *mtd, int mode) struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); unsigned long ctrl; + /* + * According to the manual: unlock the main area and set the data transfer + * direction (read or write) too + * Luis Galdos + */ ctrl = readl(info->regs + S3C2440_NFCONT); - writel(ctrl | S3C2412_NFCONT_INIT_MAIN_ECC, info->regs + S3C2440_NFCONT); + ctrl |= S3C2412_NFCONT_INIT_MAIN_ECC; + ctrl &= ~S3C2412_NFCONT_MAIN_ECC_LOCK; + + if (mode == NAND_ECC_WRITE) + ctrl |= S3C2412_NFCONT_ECC4_DIRWR; + else + ctrl &= ~S3C2412_NFCONT_ECC4_DIRWR; + + writel(ctrl, info->regs + S3C2440_NFCONT); } static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode) @@ -545,13 +554,25 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u static int s3c2412_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) { struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); - unsigned long ecc = readl(info->regs + S3C2412_NFMECC0); + unsigned long ecc, nfcont; - ecc_code[0] = ecc; - ecc_code[1] = ecc >> 8; - ecc_code[2] = ecc >> 16; + /* + * According to the manual: lock the main area before reading from the ECC + * status register. + * Luis Galdos + */ + nfcont = readl(info->regs + S3C2440_NFCONT); + nfcont |= S3C2412_NFCONT_MAIN_ECC_LOCK; + writel(nfcont, info->regs + S3C2440_NFCONT); - pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n", ecc_code[0], ecc_code[1], ecc_code[2]); + ecc = readl(info->regs + S3C2412_NFMECC0); + ecc_code[0] = ecc & 0xff; + ecc_code[1] = (ecc >> 8) & 0xff; + ecc_code[2] = (ecc >> 16) & 0xff; + ecc_code[3] = (ecc >> 24) & 0xff; + + pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x,%02x\n", + ecc_code[0], ecc_code[1], ecc_code[2], ecc_code[3]); return 0; } @@ -616,52 +637,6 @@ static void s3c2440_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int } } -/* cpufreq driver support */ - -#ifdef CONFIG_CPU_FREQ - -static int s3c2410_nand_cpufreq_transition(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct s3c2410_nand_info *info; - unsigned long newclk; - - info = container_of(nb, struct s3c2410_nand_info, freq_transition); - newclk = clk_get_rate(info->clk); - - if ((val == CPUFREQ_POSTCHANGE && newclk < info->clk_rate) || - (val == CPUFREQ_PRECHANGE && newclk > info->clk_rate)) { - s3c2410_nand_setrate(info); - } - - return 0; -} - -static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) -{ - info->freq_transition.notifier_call = s3c2410_nand_cpufreq_transition; - - return cpufreq_register_notifier(&info->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) -{ - cpufreq_unregister_notifier(&info->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -#else -static inline int s3c2410_nand_cpufreq_register(struct s3c2410_nand_info *info) -{ - return 0; -} - -static inline void s3c2410_nand_cpufreq_deregister(struct s3c2410_nand_info *info) -{ -} -#endif - /* device management functions */ static int s3c24xx_nand_remove(struct platform_device *pdev) @@ -673,8 +648,6 @@ static int s3c24xx_nand_remove(struct platform_device *pdev) if (info == NULL) return 0; - s3c2410_nand_cpufreq_deregister(info); - /* Release all our mtds and their partitions, then go through * freeing the resources used */ @@ -842,11 +815,14 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, chip->ecc.mode = NAND_ECC_SOFT; } + /* @FIXME: Here seems to be something wrong. (Luis Galdos) */ +#if 1 if (set->ecc_layout != NULL) chip->ecc.layout = set->ecc_layout; if (set->disable_ecc) chip->ecc.mode = NAND_ECC_NONE; +#endif switch (chip->ecc.mode) { case NAND_ECC_NONE: @@ -886,8 +862,7 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info, { struct nand_chip *chip = &nmtd->chip; - dev_dbg(info->device, "chip %p => page shift %d\n", - chip, chip->page_shift); + printk("%s: chip %p: %d\n", __func__, chip, chip->page_shift); if (chip->ecc.mode != NAND_ECC_HW) return; @@ -896,12 +871,19 @@ static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info, * the large or small page nand device */ if (chip->page_shift > 10) { - chip->ecc.size = 256; - chip->ecc.bytes = 3; + chip->ecc.size = 2048; + chip->ecc.bytes = 4; + chip->ecc.layout = &nand_hw_eccoob; } else { + /* + * IMPORTANT: For using only three ECC-bytes is required to set + * the fourth byte to '0xff', otherwise we can't use the internal + * NAND-controller for checking if the ECC is correct or not. + * (Luis Galdos) + */ chip->ecc.size = 512; chip->ecc.bytes = 3; - chip->ecc.layout = &nand_hw_eccoob; + chip->ecc.layout = &nand_hw_eccoob_16; } } @@ -925,6 +907,18 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) int nr_sets; int setno; + /* + * Required variables for accessing to the partitions from the command line + * Luis Galdos + */ +#if defined(CONFIG_MTD_CMDLINE_PARTS) + struct mtd_partition *mtd_parts; + int nr_parts; + const char *name_back; + struct s3c2410_nand_set nand_sets[1]; + const char *part_probes[] = { "cmdlinepart", NULL }; +#endif + cpu_type = platform_get_device_id(pdev)->driver_data; pr_debug("s3c2410_nand_probe(%p)\n", pdev); @@ -981,7 +975,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) /* initialise the hardware */ - err = s3c2410_nand_inithw(info); + err = s3c2410_nand_inithw(info, pdev); if (err != 0) goto exit_error; @@ -1013,6 +1007,29 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) (sets) ? sets->nr_chips : 1, NULL); + /* + * This is the code required for accessing to the partitions table + * passed by the bootloader + * (Luis Galdos) + */ +#if defined(CONFIG_MTD_CMDLINE_PARTS) + /* + * Need to reset the name of the MTD-device then the name of the + * partition passed by the U-Boot differs from the assigned name. + * U-Boot : onboard_boot + * Device : NAND 128MiB 3,3V 8-bit + */ + name_back = nmtd->mtd.name; + nmtd->mtd.name= PARTITON_PARAMETER_NAME; + nr_parts = parse_mtd_partitions(&nmtd->mtd, part_probes, &mtd_parts, 0); + nmtd->mtd.name = name_back; + nand_sets[0].name = "NAND-Parts"; + nand_sets[0].nr_chips = 1; + nand_sets[0].partitions = mtd_parts; + nand_sets[0].nr_partitions = nr_parts; + sets = nand_sets; +#endif /* defined(CONFIG_MTD_CMDLINE_PARTS) */ + if (nmtd->scan_res == 0) { s3c2410_nand_update_chip(info, nmtd); nand_scan_tail(&nmtd->mtd); @@ -1023,12 +1040,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) sets++; } - err = s3c2410_nand_cpufreq_register(info); - if (err < 0) { - dev_err(&pdev->dev, "failed to init cpufreq support\n"); - goto exit_error; - } - if (allow_clk_stop(info)) { dev_info(&pdev->dev, "clock idle support enabled\n"); clk_disable(info->clk); @@ -1076,7 +1087,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev) if (info) { clk_enable(info->clk); - s3c2410_nand_inithw(info); + s3c2410_nand_inithw(info, dev); /* Restore the state of the nFCE line. */ diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 67b150570265..676eea0c47f7 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1051,15 +1051,6 @@ config SMSC911X . The module will be called smsc911x. -config SMSC9118 - tristate "SMSC LAN9218 support" - depends on NET_ETHERNET && (MACH_CC9M2443JS || MACH_CCW9M2443JS) - select CRC32 - select MII - ---help--- - Say Y here if you want support for SMSC LAN921x families - of ethernet controllers. - config NET_VENDOR_RACAL bool "Racal-Interlan (Micom) NI cards" depends on ISA diff --git a/drivers/net/Makefile b/drivers/net/Makefile index d9113efccb74..a9a4f9522465 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -268,7 +268,6 @@ obj-$(CONFIG_MACB) += macb.o obj-$(CONFIG_S6GMAC) += s6gmac.o obj-$(CONFIG_ARM) += arm/ -obj-$(CONFIG_SMSC9118) += smsc9118/ obj-$(CONFIG_DEV_APPLETALK) += appletalk/ obj-$(CONFIG_TR) += tokenring/ obj-$(CONFIG_WAN) += wan/ diff --git a/drivers/net/smsc9118/Makefile b/drivers/net/smsc9118/Makefile deleted file mode 100644 index d33fe1dc8e38..000000000000 --- a/drivers/net/smsc9118/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_SMSC9118) += smsc911x.o diff --git a/drivers/net/smsc9118/smsc911x.c b/drivers/net/smsc9118/smsc911x.c deleted file mode 100644 index a71d5c042d50..000000000000 --- a/drivers/net/smsc9118/smsc911x.c +++ /dev/null @@ -1,2711 +0,0 @@ -/*************************************************************************** - * - * Copyright (C) 2004-2007 SMSC - * Copyright (C) 2005 ARM - * - * 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. - * - *************************************************************************** - * Rewritten, heavily based on smsc911x simple driver by SMSC. - * Partly uses io macros from smc91x.c by Nicolas Pitre - * - * Supported devices: - * LAN9115, LAN9116, LAN9117, LAN9118 - * LAN9215, LAN9216, LAN9217, LAN9218 - * - * History: - * 05/05/2005 bahadir.balban@arm.com - * - Transition to linux coding style - * - Platform driver and module interface - * - * 17/07/2006 steve.glendinning@smsc.com - * - Added support for LAN921x family - * - Added workaround for multicast filters - * - * 31/07/2006 steve.glendinning@smsc.com - * - Removed tasklet, using NAPI poll instead - * - Multiple device support - * - Large tidy-up following feedback from netdev list - * - * 03/08/2006 steve.glendinning@smsc.com - * - Added ethtool support - * - Convert to use generic MII interface - * - * 04/08/2006 bahadir.balban@arm.com - * - Added ethtool eeprom r/w support - * - * 17/06/2007 steve.glendinning@smsc.com - * - Incorporate changes from Bill Gatliff and Russell King - * - * 04/07/2007 steve.glendinning@smsc.com - * - move irq configuration to platform_device - * - fix link poller after interface is stopped and restarted - * - * 13/07/2007 bahadir.balban@arm.com - * - set irq polarity before requesting irq - * - * 26/06/2007 hennerich@blackfin.uclinux.org - * - Fixed minor style issue to pass checkpatch.pl - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* For having the same platform-data as in the Vanilla kernel */ -#include - -#include "smsc911x.h" - -#define SMSC_CHIPNAME "smsc911x" -#define SMSC_DRV_VERSION "2007-07-13" - -MODULE_LICENSE("GPL"); - - -/* Base address of the connected controller: S3C2410_CS5 = 0x28000000 */ -#define printk_err(fmt, args...) printk(KERN_ERR "[ ERROR ] smsc911x: " fmt, ## args) -#define printk_info(fmt, args...) printk(KERN_INFO "smsc911x: " fmt, ## args) - -#if 0 -#define SMSC911X_DEBUG -#endif - -#ifdef SMSC911X_DEBUG -# define printk_debug(fmt, args...) printk(KERN_DEBUG "smsc911x: " fmt, ## args) -#else -# define printk_debug(fmt, args...) -#endif - -/* Enables the debug messages for the PM-operations (WOL, suspend, etc.) */ -#if 0 -#define SMSC911X_PM_DEBUG -#endif - -#ifdef SMSC911X_PM_DEBUG -# define printk_pmdbg(fmt, args...) printk(KERN_DEBUG "smsc911x: " fmt, ## args) -#else -# define printk_pmdbg(fmt, args...) -#endif - -struct smsc911x_data { - void __iomem *ioaddr; - - unsigned int idrev; - unsigned int generation; /* used to decide which workarounds apply */ - - /* device configuration */ - unsigned int irq_polarity; - unsigned int irq_type; - unsigned int irq_flags; - - /* This needs to be acquired before calling any of below: - * smsc911x_mac_read(), smsc911x_mac_write() - * smsc911x_phy_read(), smsc911x_phy_write() - */ - spinlock_t phy_lock; - - struct mii_if_info mii; - unsigned int using_extphy; - u32 msg_enable; -#ifdef USE_LED1_WORK_AROUND - unsigned int gpio_setting; - unsigned int gpio_orig_setting; -#endif - struct net_device *netdev; - struct napi_struct napi; - struct timer_list link_poll_timer; - unsigned int stop_link_poll; - - unsigned int software_irq_signal; - -#ifdef USE_PHY_WORK_AROUND -#define MIN_PACKET_SIZE (64) - char loopback_tx_pkt[MIN_PACKET_SIZE]; - char loopback_rx_pkt[MIN_PACKET_SIZE]; - unsigned int resetcount; -#endif - - /* Members for Multicast filter workaround */ - unsigned int multicast_update_pending; - unsigned int set_bits_mask; - unsigned int clear_bits_mask; - unsigned int hashhi; - unsigned int hashlo; - unsigned int last_rxstat; - - /* Registers for the internal PM */ - unsigned long mac_wucsr; - unsigned long pmt_ctrl; - unsigned long phy_intmsk; -}; - - -static int smsc911x_set_mac(struct net_device *dev, void *addr); - -#if SMSC_CAN_USE_32BIT - -static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) -{ - return readl(pdata->ioaddr + reg); -} - -static inline void smsc911x_reg_write(u32 val, struct smsc911x_data *pdata, - u32 reg) -{ - writel(val, pdata->ioaddr + reg); -} - -#else /* SMSC_CAN_USE_32BIT */ - -static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) -{ - u32 reg_val; - unsigned long flags; - - /* these two 16-bit reads must be performed consecutively, so must - * not be interrupted by our own ISR (which would start another - * read operation) */ - local_irq_save(flags); - reg_val = ((readw(pdata->ioaddr + reg) & 0xFFFF) | - ((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16)); - local_irq_restore(flags); - - return reg_val; -} - -static inline void smsc911x_reg_write(u32 val, struct smsc911x_data *pdata, - u32 reg) -{ - unsigned long flags; - - /* these two 16-bit writes must be performed consecutively, so must - * not be interrupted by our own ISR (which would start another - * read operation) */ - local_irq_save(flags); - writew(val & 0xFFFF, pdata->ioaddr + reg); - writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2); - local_irq_restore(flags); -} - -#endif /* SMSC_CAN_USE_32BIT */ - -#ifndef CONFIG_BLACKFIN -/* Writes a packet to the TX_DATA_FIFO */ -static inline void -smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf, - unsigned int wordcount) -{ - while (wordcount--) - smsc911x_reg_write(*buf++, pdata, TX_DATA_FIFO); -} - -/* Reads a packet out of the RX_DATA_FIFO */ -static inline void -smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, - unsigned int wordcount) -{ - while (wordcount--) - *buf++ = smsc911x_reg_read(pdata, RX_DATA_FIFO); -} -#else -/* Writes a packet to the TX_DATA_FIFO */ -static inline void -smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf, - unsigned int wordcount) -{ - if (wordcount > 24) - dma_outsl((u_long)pdata->ioaddr + TX_DATA_FIFO, buf, wordcount); - else - outsl((u_long)pdata->ioaddr + TX_DATA_FIFO, buf, wordcount); -} - -/* Reads a packet out of the RX_DATA_FIFO */ -static inline void -smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, - unsigned int wordcount) -{ - if (wordcount > 24) - dma_insl((u_long)pdata->ioaddr + RX_DATA_FIFO, buf, wordcount); - else - insl((u_long)pdata->ioaddr + RX_DATA_FIFO, buf, wordcount); -} -#endif - -/* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read - * and smsc911x_mac_write, so assumes phy_lock is held */ -static int smsc911x_mac_notbusy(struct smsc911x_data *pdata) -{ - int i; - u32 val; - - for (i = 0; i < 40; i++) { - val = smsc911x_reg_read(pdata, MAC_CSR_CMD); - if (!(val & MAC_CSR_CMD_CSR_BUSY_)) - return 1; - } - SMSC_WARNING("Timed out waiting for MAC not BUSY. " - "MAC_CSR_CMD: 0x%08X", val); - return 0; -} - -/* Fetches a MAC register value. Assumes phy_lock is acquired */ -static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset) -{ - unsigned int temp; - -#ifdef CONFIG_DEBUG_SPINLOCK - if (!spin_is_locked(&pdata->phy_lock)) - SMSC_WARNING("phy_lock not held"); -#endif /* CONFIG_DEBUG_SPINLOCK */ - - temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); - if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { - SMSC_WARNING("smsc911x_mac_read failed, MAC busy at entry"); - return 0xFFFFFFFF; - } - - /* Send the MAC cmd */ - smsc911x_reg_write(((offset & 0xFF) | MAC_CSR_CMD_CSR_BUSY_ - | MAC_CSR_CMD_R_NOT_W_), pdata, MAC_CSR_CMD); - - /* Workaround for hardware read-after-write restriction */ - temp = smsc911x_reg_read(pdata, BYTE_TEST); - - /* Wait for the read to happen */ - if (likely(smsc911x_mac_notbusy(pdata))) - return smsc911x_reg_read(pdata, MAC_CSR_DATA); - - SMSC_WARNING("smsc911x_mac_read failed, MAC busy after read"); - return 0xFFFFFFFF; -} - -/* Set a mac register, phy_lock must be acquired before calling */ -static void smsc911x_mac_write(struct smsc911x_data *pdata, - unsigned int offset, u32 val) -{ - unsigned int temp; - -#ifdef CONFIG_DEBUG_SPINLOCK - if (!spin_is_locked(&pdata->phy_lock)) - SMSC_WARNING("phy_lock not held"); -#endif /* CONFIG_DEBUG_SPINLOCK */ - - temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); - if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { - SMSC_WARNING("smsc911x_mac_write failed, MAC busy at entry"); - return; - } - - /* Send data to write */ - smsc911x_reg_write(val, pdata, MAC_CSR_DATA); - - /* Write the actual data */ - smsc911x_reg_write(((offset & 0xFF) | MAC_CSR_CMD_CSR_BUSY_), pdata, - MAC_CSR_CMD); - - /* Workaround for hardware read-after-write restriction */ - temp = smsc911x_reg_read(pdata, BYTE_TEST); - - /* Wait for the write to complete */ - if (likely(smsc911x_mac_notbusy(pdata))) - return; - - SMSC_WARNING("smsc911x_mac_write failed, MAC busy after write"); -} - -/* Gets a phy register, phy_lock must be acquired before calling */ -static u16 smsc911x_phy_read(struct smsc911x_data *pdata, unsigned int index) -{ - unsigned int addr; - int i; - -#ifdef CONFIG_DEBUG_SPINLOCK - if (!spin_is_locked(&pdata->phy_lock)) - SMSC_WARNING("phy_lock not held"); -#endif /* CONFIG_DEBUG_SPINLOCK */ - - /* Confirm MII not busy */ - if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - SMSC_WARNING("MII is busy in smsc911x_phy_read???"); - return 0; - } - - /* Set the address, index & direction (read from PHY) */ - addr = (((pdata->mii.phy_id) & 0x1F) << 11) - | ((index & 0x1F) << 6); - smsc911x_mac_write(pdata, MII_ACC, addr); - - /* Wait for read to complete w/ timeout */ - for (i = 0; i < 100; i++) { - /* See if MII is finished yet */ - if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - return smsc911x_mac_read(pdata, MII_DATA); - } - } - SMSC_WARNING("Timed out waiting for MII write to finish"); - return 0xFFFF; -} - -/* Sets a phy register, phy_lock must be acquired before calling */ -static void smsc911x_phy_write(struct smsc911x_data *pdata, - unsigned int index, u16 val) -{ - unsigned int addr; - int i; - -#ifdef CONFIG_DEBUG_SPINLOCK - if (!spin_is_locked(&pdata->phy_lock)) - SMSC_WARNING("phy_lock not held"); -#endif /* CONFIG_DEBUG_SPINLOCK */ - - /* Confirm MII not busy */ - if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { - SMSC_WARNING("MII is busy in smsc911x_write_phy???"); - return; - } - - /* Put the data to write in the MAC */ - smsc911x_mac_write(pdata, MII_DATA, val); - - /* Set the address, index & direction (write to PHY) */ - addr = (((pdata->mii.phy_id) & 0x1F) << 11) | - ((index & 0x1F) << 6) | MII_ACC_MII_WRITE_; - smsc911x_mac_write(pdata, MII_ACC, addr); - - /* Wait for write to complete w/ timeout */ - for (i = 0; i < 100; i++) { - /* See if MII is finished yet */ - if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) - return; - } - SMSC_WARNING("Timed out waiting for MII write to finish"); -} - -static int smsc911x_mdio_read(struct net_device *dev, int phy_id, int location) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned long flags; - int reg; - - spin_lock_irqsave(&pdata->phy_lock, flags); - reg = smsc911x_phy_read(pdata, location); - spin_unlock_irqrestore(&pdata->phy_lock, flags); - - return reg; -} - -static void smsc911x_mdio_write(struct net_device *dev, int phy_id, - int location, int val) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&pdata->phy_lock, flags); - smsc911x_phy_write(pdata, location, val); - spin_unlock_irqrestore(&pdata->phy_lock, flags); -} - -/* Autodetects and initialises external phy for SMSC9115 and SMSC9117 flavors. - * If something goes wrong, returns -ENODEV to revert back to internal phy. - * Performed at initialisation only, so interrupts are enabled */ -static int smsc911x_phy_initialise_external(struct smsc911x_data *pdata) -{ - unsigned int address; - unsigned int hwcfg; - unsigned int phyid1; - unsigned int phyid2; - - hwcfg = smsc911x_reg_read(pdata, HW_CFG); - - /* External phy is requested, supported, and detected */ - if (hwcfg & HW_CFG_EXT_PHY_DET_) { - - /* Attempt to switch to external phy for auto-detecting - * its address. Assuming tx and rx are stopped because - * smsc911x_phy_initialise is called before - * smsc911x_rx_initialise and tx_initialise. - */ - - /* Disable phy clocks to the MAC */ - hwcfg &= (~HW_CFG_PHY_CLK_SEL_); - hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_; - smsc911x_reg_write(hwcfg, pdata, HW_CFG); - udelay(10); /* Enough time for clocks to stop */ - - /* Switch to external phy */ - hwcfg |= HW_CFG_EXT_PHY_EN_; - smsc911x_reg_write(hwcfg, pdata, HW_CFG); - - /* Enable phy clocks to the MAC */ - hwcfg &= (~HW_CFG_PHY_CLK_SEL_); - hwcfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_; - smsc911x_reg_write(hwcfg, pdata, HW_CFG); - udelay(10); /* Enough time for clocks to restart */ - - hwcfg |= HW_CFG_SMI_SEL_; - smsc911x_reg_write(hwcfg, pdata, HW_CFG); - - /* Auto-detect PHY */ - spin_lock_irq(&pdata->phy_lock); - for (address = 0; address <= 31; address++) { - pdata->mii.phy_id = address; - phyid1 = smsc911x_phy_read(pdata, MII_PHYSID1); - phyid2 = smsc911x_phy_read(pdata, MII_PHYSID2); - if ((phyid1 != 0xFFFFU) || (phyid2 != 0xFFFFU)) { - SMSC_TRACE("Detected PHY at address = " - "0x%02X = %d", address, address); - break; - } - } - spin_unlock_irq(&pdata->phy_lock); - - if ((phyid1 == 0xFFFFU) && (phyid2 == 0xFFFFU)) { - SMSC_WARNING("External PHY is not accessable, " - "using internal PHY instead"); - /* Revert back to internal phy settings. */ - - /* Disable phy clocks to the MAC */ - hwcfg &= (~HW_CFG_PHY_CLK_SEL_); - hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_; - smsc911x_reg_write(hwcfg, pdata, HW_CFG); - udelay(10); /* Enough time for clocks to stop */ - - /* Switch to internal phy */ - hwcfg &= (~HW_CFG_EXT_PHY_EN_); - smsc911x_reg_write(hwcfg, pdata, HW_CFG); - - /* Enable phy clocks to the MAC */ - hwcfg &= (~HW_CFG_PHY_CLK_SEL_); - hwcfg |= HW_CFG_PHY_CLK_SEL_INT_PHY_; - smsc911x_reg_write(hwcfg, pdata, HW_CFG); - udelay(10); /* Enough time for clocks to restart */ - - hwcfg &= (~HW_CFG_SMI_SEL_); - smsc911x_reg_write(hwcfg, pdata, HW_CFG); - /* Use internal phy */ - return -ENODEV; - } else { - SMSC_TRACE("Successfully switched to external PHY"); - pdata->using_extphy = 1; - } - } else { - SMSC_WARNING("No external PHY detected."); - SMSC_WARNING("Using internal PHY instead."); - /* Use internal phy */ - return -ENODEV; - } - return 0; -} - -/* called by phy_initialise and loopback test */ -static int smsc911x_phy_reset(struct smsc911x_data *pdata) -{ - unsigned int temp; - unsigned int i = 100000; - unsigned long flags; - - SMSC_TRACE("Performing PHY BCR Reset"); - spin_lock_irqsave(&pdata->phy_lock, flags); - smsc911x_phy_write(pdata, MII_BMCR, BMCR_RESET); - do { - udelay(10); - temp = smsc911x_phy_read(pdata, MII_BMCR); - } while ((i--) && (temp & BMCR_RESET)); - spin_unlock_irqrestore(&pdata->phy_lock, flags); - - if (temp & BMCR_RESET) { - SMSC_WARNING("PHY reset failed to complete."); - return 0; - } - /* Extra delay required because the phy may not be completed with - * its reset when BMCR_RESET is cleared. Specs say 256 uS is - * enough delay but using 1ms here to be safe - */ - msleep(1); - - return 1; -} - -/* Fetches a tx status out of the status fifo */ -static unsigned int smsc911x_tx_get_txstatus(struct smsc911x_data *pdata) -{ - unsigned int result = - smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TSUSED_; - - if (result != 0) - result = smsc911x_reg_read(pdata, TX_STATUS_FIFO); - - return result; -} - -/* Fetches the next rx status */ -static unsigned int smsc911x_rx_get_rxstatus(struct smsc911x_data *pdata) -{ - unsigned int result = - smsc911x_reg_read(pdata, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED_; - - if (result != 0) - result = smsc911x_reg_read(pdata, RX_STATUS_FIFO); - - return result; -} - -#ifdef USE_PHY_WORK_AROUND -static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) -{ - unsigned int tries; - u32 wrsz; - u32 rdsz; - u32 bufp; - - for (tries = 0; tries < 10; tries++) { - unsigned int txcmd_a; - unsigned int txcmd_b; - unsigned int status; - unsigned int pktlength; - unsigned int i; - - /* Zero-out rx packet memory */ - memset(pdata->loopback_rx_pkt, 0, MIN_PACKET_SIZE); - - /* Write tx packet to 118 */ - txcmd_a = (((unsigned int)pdata->loopback_tx_pkt) - & 0x03) << 16; - txcmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; - txcmd_a |= MIN_PACKET_SIZE; - - txcmd_b = MIN_PACKET_SIZE << 16 | MIN_PACKET_SIZE; - - smsc911x_reg_write(txcmd_a, pdata, TX_DATA_FIFO); - smsc911x_reg_write(txcmd_b, pdata, TX_DATA_FIFO); - - bufp = ((u32) pdata->loopback_tx_pkt) & 0xFFFFFFFC; - wrsz = MIN_PACKET_SIZE + 3; - wrsz += (((u32) pdata->loopback_tx_pkt) & 0x3); - wrsz >>= 2; - - smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); - - /* Wait till transmit is done */ - i = 60; - do { - udelay(5); - status = smsc911x_tx_get_txstatus(pdata); - } while ((i--) && (!status)); - - if (!status) { - SMSC_WARNING("Failed to transmit during loopback test"); - continue; - } - if (status & TX_STS_ES_) { - SMSC_WARNING("Transmit encountered errors during " - "loopback test"); - continue; - } - - /* Wait till receive is done */ - i = 60; - do { - udelay(5); - status = smsc911x_rx_get_rxstatus(pdata); - } while ((i--) && (!status)); - - if (!status) { - SMSC_WARNING("Failed to receive during loopback test"); - continue; - } - if (status & RX_STS_ES_) { - SMSC_WARNING("Receive encountered errors during " - "loopback test"); - continue; - } - - pktlength = ((status & 0x3FFF0000UL) >> 16); - bufp = (u32)pdata->loopback_rx_pkt; - rdsz = pktlength + 3; - rdsz += ((u32)pdata->loopback_rx_pkt) & 0x3; - rdsz >>= 2; - - smsc911x_rx_readfifo(pdata, (unsigned int *)bufp, rdsz); - - if (pktlength != (MIN_PACKET_SIZE + 4)) { - SMSC_WARNING("Unexpected packet size during " - "loop back test, size=%d, " - "will retry", pktlength); - } else { - unsigned int j; - int mismatch = 0; - for (j = 0; j < MIN_PACKET_SIZE; j++) { - if (pdata->loopback_tx_pkt[j] - != pdata->loopback_rx_pkt[j]) { - mismatch = 1; - break; - } - } - if (!mismatch) { - SMSC_TRACE("Successfully verified " - "loopback packet"); - return 1; - } else { - SMSC_WARNING("Data miss match during " - "loop back test, will retry."); - } - } - } - - return 0; -} - -static int smsc911x_phy_loopbacktest(struct smsc911x_data *pdata) -{ - int result = 0; - unsigned int i; - unsigned int val; - unsigned long flags; - - /* Initialise tx packet */ - for (i = 0; i < 6; i++) { - /* Use broadcast destination address */ - pdata->loopback_tx_pkt[i] = (char)0xFF; - } - - for (i = 6; i < 12; i++) { - /* Use incrementing source address */ - pdata->loopback_tx_pkt[i] = (char)i; - } - - /* Set length type field */ - pdata->loopback_tx_pkt[12] = 0x00; - pdata->loopback_tx_pkt[13] = 0x00; - for (i = 14; i < MIN_PACKET_SIZE; i++) { - pdata->loopback_tx_pkt[i] = (char)i; - } - - val = smsc911x_reg_read(pdata, HW_CFG); - val &= HW_CFG_TX_FIF_SZ_; - val |= HW_CFG_SF_; - smsc911x_reg_write(val, pdata, HW_CFG); - - smsc911x_reg_write(TX_CFG_TX_ON_, pdata, TX_CFG); - smsc911x_reg_write((((unsigned int)pdata->loopback_rx_pkt) - & 0x03) << 8, pdata, RX_CFG); - - for (i = 0; i < 10; i++) { - /* Set PHY to 10/FD, no ANEG, and loopback mode */ - spin_lock_irqsave(&pdata->phy_lock, flags); - smsc911x_phy_write(pdata, MII_BMCR, 0x4100); - - /* Enable MAC tx/rx, FD */ - smsc911x_mac_write(pdata, MAC_CR, MAC_CR_FDPX_ - | MAC_CR_TXEN_ | MAC_CR_RXEN_); - spin_unlock_irqrestore(&pdata->phy_lock, flags); - - if (smsc911x_phy_check_loopbackpkt(pdata)) { - result = 1; - break; - } - pdata->resetcount++; - - /* Disable MAC rx */ - spin_lock_irqsave(&pdata->phy_lock, flags); - smsc911x_mac_write(pdata, MAC_CR, 0); - spin_unlock_irqrestore(&pdata->phy_lock, flags); - - smsc911x_phy_reset(pdata); - } - - /* Disable MAC */ - spin_lock_irqsave(&pdata->phy_lock, flags); - smsc911x_mac_write(pdata, MAC_CR, 0); - - /* Cancel PHY loopback mode */ - smsc911x_phy_write(pdata, MII_BMCR, 0); - spin_unlock_irqrestore(&pdata->phy_lock, flags); - - smsc911x_reg_write(0, pdata, TX_CFG); - smsc911x_reg_write(0, pdata, RX_CFG); - - return result; -} -#endif /* USE_PHY_WORK_AROUND */ - - -inline static void smsc911x_phy_dump_regs(struct smsc911x_data *pdata) -{ - printk("BCR = 0x%04x\n", smsc911x_phy_read(pdata, MII_BMCR)); - printk("BSR = 0x%04x\n", smsc911x_phy_read(pdata, MII_BMSR)); - printk("ID1 = 0x%04x\n", smsc911x_phy_read(pdata, MII_PHYSID1)); - printk("ID2 = 0x%04x\n", smsc911x_phy_read(pdata, MII_PHYSID2)); - printk("ADVER = 0x%04x\n", smsc911x_phy_read(pdata, MII_ADVERTISE)); - printk("LPA = 0x%04x\n", smsc911x_phy_read(pdata, MII_LPA)); - printk("EXP = 0x%04x\n", smsc911x_phy_read(pdata, MII_EXPANSION)); -} - -/* assumes phy_lock is held */ -static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata) -{ - unsigned int temp; - - if (pdata->mii.full_duplex) { - unsigned int phy_adv; - unsigned int phy_lpa; - phy_adv = smsc911x_phy_read(pdata, MII_ADVERTISE); - phy_lpa = smsc911x_phy_read(pdata, MII_LPA); - if (phy_adv & phy_lpa & LPA_PAUSE_CAP) { - /* Both ends support symmetric pause, enable - * PAUSE receive and transmit */ - smsc911x_mac_write(pdata, FLOW, 0xFFFF0002); - temp = smsc911x_reg_read(pdata, AFC_CFG); - temp |= 0xF; - smsc911x_reg_write(temp, pdata, AFC_CFG); - } else if (((phy_adv & ADVERTISE_PAUSE_ALL) == - ADVERTISE_PAUSE_ALL) && - ((phy_lpa & LPA_PAUSE_ALL) == LPA_PAUSE_ASYM)) { - /* We support symmetric and asym pause, the - * other end only supports asym, Enable PAUSE - * receive, disable PAUSE transmit */ - smsc911x_mac_write(pdata, FLOW, 0xFFFF0002); - temp = smsc911x_reg_read(pdata, AFC_CFG); - temp &= ~0xF; - smsc911x_reg_write(temp, pdata, AFC_CFG); - } else { - /* Disable PAUSE receive and transmit */ - smsc911x_mac_write(pdata, FLOW, 0); - temp = smsc911x_reg_read(pdata, AFC_CFG); - temp &= ~0xF; - smsc911x_reg_write(temp, pdata, AFC_CFG); - } - } else { - smsc911x_mac_write(pdata, FLOW, 0); - temp = smsc911x_reg_read(pdata, AFC_CFG); - temp |= 0xF; - smsc911x_reg_write(temp, pdata, AFC_CFG); - } -} - -static void smsc911x_phy_update_duplex(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned long flags; - unsigned int mac_cr; - - spin_lock_irqsave(&pdata->phy_lock, flags); - - mac_cr = smsc911x_mac_read(pdata, MAC_CR); - if (pdata->mii.full_duplex) { - SMSC_TRACE("configuring for full duplex mode"); - mac_cr |= MAC_CR_FDPX_; - } else { - SMSC_TRACE("configuring for half duplex mode"); - mac_cr &= ~MAC_CR_FDPX_; - } - smsc911x_mac_write(pdata, MAC_CR, mac_cr); - smsc911x_phy_update_flowcontrol(pdata); - - spin_unlock_irqrestore(&pdata->phy_lock, flags); -} - - -/* Update link mode if any thing has changed */ -static void smsc911x_phy_update_linkmode(struct net_device *dev, int init) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - - if (mii_check_media(&pdata->mii, netif_msg_link(pdata), init)) - smsc911x_phy_update_duplex(dev); - /* mii_check_media() exists if the media is forced... */ - if (pdata->mii.force_media) { - int cur_link = mii_link_ok(&pdata->mii); - int prev_link = netif_carrier_ok(dev); - - if (!prev_link && cur_link) { - printk(KERN_INFO "%s: link up\n", dev->name); - netif_carrier_on(dev); - } else if (prev_link && !cur_link) { - printk(KERN_INFO "%s: link down\n", dev->name); - netif_carrier_off(dev); - } - } - -#ifdef USE_LED1_WORK_AROUND - if (netif_carrier_ok(dev)) { - if ((pdata->gpio_orig_setting & GPIO_CFG_LED1_EN_) && - (!pdata->using_extphy)) { - /* Restore orginal GPIO configuration */ - pdata->gpio_setting = pdata->gpio_orig_setting; - smsc911x_reg_write(pdata->gpio_setting, pdata, - GPIO_CFG); - } - } else { - /* Check global setting that LED1 - * usage is 10/100 indicator */ - pdata->gpio_setting = smsc911x_reg_read(pdata, GPIO_CFG); - if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_) - && (!pdata->using_extphy)) { - /* Force 10/100 LED off, after saving - * orginal GPIO configuration */ - pdata->gpio_orig_setting = pdata->gpio_setting; - - pdata->gpio_setting &= ~GPIO_CFG_LED1_EN_; - pdata->gpio_setting |= (GPIO_CFG_GPIOBUF0_ - | GPIO_CFG_GPIODIR0_ - | GPIO_CFG_GPIOD0_); - smsc911x_reg_write(pdata->gpio_setting, pdata, - GPIO_CFG); - } - } -#endif /* USE_LED1_WORK_AROUND */ -} - -/* Entry point for the link poller */ -static void smsc911x_phy_checklink(unsigned long ptr) -{ - struct net_device *dev = (struct net_device *)ptr; - struct smsc911x_data *pdata = netdev_priv(dev); - - smsc911x_phy_update_linkmode(dev, 0); - - if (!(pdata->stop_link_poll)) { - pdata->link_poll_timer.expires = jiffies + 2 * HZ; - add_timer(&pdata->link_poll_timer); - } else { - pdata->stop_link_poll = 0; - } -} - -static void smsc911x_phy_set_automdx(struct smsc911x_data *pdata) -{ - u16 ctrlstatus; - - ctrlstatus = smsc911x_phy_read(pdata, 27); - ctrlstatus &= 0x1fff; - ctrlstatus |= (0x6 << 13); - smsc911x_phy_write(pdata, 27, ctrlstatus); -} - -/* Initialises the PHY layer. Called at initialisation by open() so - * interrupts are enabled */ -static int smsc911x_phy_initialise(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned int phyid1 = 0; - unsigned int phyid2 = 0; - unsigned int temp; - - printk_debug("Calling phy_initialise()\n"); - - pdata->using_extphy = 0; - - switch (pdata->idrev & 0xFFFF0000) { - case 0x01170000: - case 0x01150000: - /* External PHY supported, try to autodetect */ - if (smsc911x_phy_initialise_external(pdata) < 0) { - SMSC_TRACE("External PHY is not detected, using " - "internal PHY instead"); - pdata->mii.phy_id = 1; - } - break; - default: - SMSC_TRACE("External PHY is not supported, using internal PHY " - "instead"); - pdata->mii.phy_id = 1; - break; - } - - spin_lock_irq(&pdata->phy_lock); - phyid1 = smsc911x_phy_read(pdata, MII_PHYSID1); - phyid2 = smsc911x_phy_read(pdata, MII_PHYSID2); - spin_unlock_irq(&pdata->phy_lock); - - if ((phyid1 == 0xFFFF) && (phyid2 == 0xFFFF)) { - SMSC_WARNING("Internal PHY not detected!"); - return 0; - } - - /* Reset the phy */ - if (!smsc911x_phy_reset(pdata)) { - SMSC_WARNING("PHY reset failed to complete."); - return 0; - } -#ifdef USE_PHY_WORK_AROUND - if (!smsc911x_phy_loopbacktest(pdata)) { - SMSC_WARNING("Failed Loop Back Test"); - return 0; - } else { - SMSC_TRACE("Passed Loop Back Test"); - } -#endif /* USE_PHY_WORK_AROUND */ - - - smsc911x_phy_set_automdx(pdata); - - /* Advertise all speeds and pause capabilities */ - spin_lock_irq(&pdata->phy_lock); - temp = smsc911x_phy_read(pdata, MII_ADVERTISE); - temp |= (ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); - smsc911x_phy_write(pdata, MII_ADVERTISE, temp); - pdata->mii.advertising = temp; - - if (!pdata->using_extphy) { - /* using internal phy, enable PHY interrupts */ - smsc911x_phy_read(pdata, MII_INTSTS); - smsc911x_phy_write(pdata, MII_INTMSK, PHY_INTMSK_DEFAULT_); - } - - /* begin to establish link */ - smsc911x_phy_write(pdata, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); - spin_unlock_irq(&pdata->phy_lock); - - smsc911x_phy_update_linkmode(dev, 1); - - pdata->stop_link_poll = 0; - setup_timer(&pdata->link_poll_timer, smsc911x_phy_checklink, - (unsigned long)dev); - pdata->link_poll_timer.expires = jiffies + 2 * HZ; - add_timer(&pdata->link_poll_timer); - - printk_debug("PHY initialised succesfully\n"); - return 1; -} - -/* Gets the number of tx statuses in the fifo */ -static unsigned int smsc911x_tx_get_txstatcount(struct smsc911x_data *pdata) -{ - unsigned int result = (smsc911x_reg_read(pdata, TX_FIFO_INF) - & TX_FIFO_INF_TSUSED_) >> 16; - return result; -} - -/* Reads tx statuses and increments counters where necessary */ -static void smsc911x_tx_update_txcounters(struct smsc911x_data *pdata) -{ - struct net_device *netdev = pdata->netdev; - unsigned int tx_stat; - - while ((tx_stat = smsc911x_tx_get_txstatus(pdata)) != 0) { - if (unlikely(tx_stat & 0x80000000)) { - /* In this driver the packet tag is used as the packet - * length. Since a packet length can never reach the - * size of 0x8000, this bit is reserved. It is worth - * noting that the "reserved bit" in the warning above - * does not reference a hardware defined reserved bit - * but rather a driver defined one. - */ - SMSC_WARNING("Packet tag reserved bit is high"); - } else { - if (unlikely(tx_stat & 0x00008000)) { - printk_debug("TX status error: 0x%08x (MAC 0x%08x)\n", - tx_stat, smsc911x_mac_read(pdata, MAC_CR)); - netdev->stats.tx_errors++; - } else { - netdev->stats.tx_packets++; - netdev->stats.tx_bytes += (tx_stat >> 16); - } - if (unlikely(tx_stat & 0x00000100)) { - netdev->stats.collisions += 16; - netdev->stats.tx_aborted_errors += 1; - } else { - netdev->stats.collisions += - ((tx_stat >> 3) & 0xF); - } - if (unlikely(tx_stat & 0x00000800)) { - netdev->stats.tx_carrier_errors += 1; - } - if (unlikely(tx_stat & 0x00000200)) { - netdev->stats.collisions++; - netdev->stats.tx_aborted_errors++; - } - } - } -} - -/* Increments the Rx error counters */ -static void -smsc911x_rx_counterrors(struct smsc911x_data *pdata, unsigned int rxstat) -{ - struct net_device *netdev = pdata->netdev; - int crc_err = 0; - - if (unlikely(rxstat & 0x00008000)) { - netdev->stats.rx_errors++; - if (unlikely(rxstat & 0x00000002)) { - netdev->stats.rx_crc_errors++; - crc_err = 1; - } - } - if (likely(!crc_err)) { - if (unlikely((rxstat & 0x00001020) == 0x00001020)) { - /* Frame type indicates length, - * and length error is set */ - netdev->stats.rx_length_errors++; - } - if (rxstat & RX_STS_MCAST_) - netdev->stats.multicast++; - } -} - -/* Quickly dumps bad packets */ -static void -smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes) -{ - unsigned int pktwords = (pktbytes + NET_IP_ALIGN + 3) >> 2; - - if (likely(pktwords >= 4)) { - unsigned int timeout = 500; - unsigned int val; - smsc911x_reg_write(RX_DP_CTRL_RX_FFWD_, pdata, RX_DP_CTRL); - do { - udelay(1); - val = smsc911x_reg_read(pdata, RX_DP_CTRL); - } while (timeout-- && (val & RX_DP_CTRL_RX_FFWD_)); - - if (unlikely(timeout == 0)) - SMSC_WARNING("Timed out waiting for RX FFWD " - "to finish, RX_DP_CTRL: 0x%08X", val); - } else { - unsigned int temp; - while (pktwords--) - temp = smsc911x_reg_read(pdata, RX_DATA_FIFO); - } -} - -/* NAPI poll function */ -static int smsc911x_poll(struct napi_struct *napi, int budget) -{ - struct smsc911x_data *pdata = container_of(napi, struct smsc911x_data, napi); - struct net_device *dev = pdata->netdev; - int npackets = 0; - - while (npackets < budget) { - unsigned int pktlength; - unsigned int pktwords; - unsigned int rxstat = smsc911x_rx_get_rxstatus(pdata); - - /* break out of while loop if there are no more packets waiting */ - if (!rxstat) { - printk_debug("Stopping the RX poll\n"); - break; - } - - pktlength = ((rxstat & 0x3FFF0000) >> 16); - pktwords = (pktlength + NET_IP_ALIGN + 3) >> 2; - printk_debug("Going to read %i words (pktlen %i)\n", - pktwords, pktlength); - - smsc911x_rx_counterrors(pdata, rxstat); - - if (likely((rxstat & RX_STS_ES_) == 0)) { - struct sk_buff *skb; - skb = dev_alloc_skb(pktlength + NET_IP_ALIGN); - if (likely(skb)) { - skb->data = skb->head; - skb->tail = skb->head; - /* Align IP on 16B boundary */ - skb_reserve(skb, NET_IP_ALIGN); - skb_put(skb, pktlength - 4); - smsc911x_rx_readfifo(pdata, - (unsigned int *)skb->head, - pktwords); - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - skb->ip_summed = CHECKSUM_NONE; - netif_receive_skb(skb); - - /* Update counters */ - dev->stats.rx_packets++; - dev->stats.rx_bytes += (pktlength - 4); - dev->last_rx = jiffies; - npackets++; - continue; - } else { - SMSC_WARNING("Unable to allocate sk_buff " - "for rx packet, in PIO path"); - dev->stats.rx_dropped++; - } - } - /* At this point, the packet is to be read out - * of the fifo and discarded */ - smsc911x_rx_fastforward(pdata, pktlength); - } - - dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP); - smsc911x_reg_write(INT_STS_RSFL_, pdata, INT_STS); - - if (npackets < budget) { - unsigned int temp; - /* We processed all packets available. Tell NAPI it can - * stop polling then re-enable rx interrupts */ - napi_complete(napi); - temp = smsc911x_reg_read(pdata, INT_EN); - temp |= INT_EN_RSFL_EN_; - smsc911x_reg_write(temp, pdata, INT_EN); - } - - /* Return total received packets */ - return npackets; -} - -/* Returns hash bit number for given MAC address - * Example: - * 01 00 5E 00 00 01 -> returns bit number 31 */ -static unsigned int smsc911x_hash(char addr[ETH_ALEN]) -{ - unsigned int crc; - unsigned int result; - - crc = ether_crc(ETH_ALEN, addr); - result = (crc >> 26) & 0x3f; - - return result; -} - -static void smsc911x_rx_multicast_update(struct smsc911x_data *pdata) -{ - /* Performs the multicast & mac_cr update. This is called when - * safe on the current hardware, and with the phy_lock held */ - unsigned int mac_cr = smsc911x_mac_read(pdata, MAC_CR); - mac_cr |= pdata->set_bits_mask; - mac_cr &= ~(pdata->clear_bits_mask); - smsc911x_mac_write(pdata, MAC_CR, mac_cr); - smsc911x_mac_write(pdata, HASHH, pdata->hashhi); - smsc911x_mac_write(pdata, HASHL, pdata->hashlo); -} - -static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata) -{ - unsigned int mac_cr; - - /* This function is only called for older LAN911x devices - * (revA or revB), where MAC_CR, HASHH and HASHL should not - * be modified during Rx - newer devices immediately update the - * registers. - * - * This is called from interrupt context */ - - spin_lock(&pdata->phy_lock); - - /* Check Rx has stopped */ - if (smsc911x_mac_read(pdata, MAC_CR) & MAC_CR_RXEN_) - SMSC_WARNING("Rx not stopped\n"); - - /* Perform the update - safe to do now Rx has stopped */ - smsc911x_rx_multicast_update(pdata); - - /* Re-enable Rx */ - mac_cr = smsc911x_mac_read(pdata, MAC_CR); - mac_cr |= MAC_CR_RXEN_; - smsc911x_mac_write(pdata, MAC_CR, mac_cr); - - pdata->multicast_update_pending = 0; - - spin_unlock(&pdata->phy_lock); -} - -/* Sets the device MAC address to dev_addr, called with phy_lock held */ -static void -smsc911x_set_mac_address(struct smsc911x_data *pdata, u8 dev_addr[6]) -{ - u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4]; - u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | - (dev_addr[1] << 8) | dev_addr[0]; - - smsc911x_mac_write(pdata, ADDRH, mac_high16); - smsc911x_mac_write(pdata, ADDRL, mac_low32); -} - -static int smsc911x_open(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned int timeout; - unsigned int temp; - unsigned int intcfg = 0; - struct sockaddr addr; - - /* Reset the LAN911x */ - smsc911x_reg_write(HW_CFG_SRST_, pdata, HW_CFG); - timeout = 10; - do { - udelay(10); - temp = smsc911x_reg_read(pdata, HW_CFG); - } while ((--timeout) && (temp & HW_CFG_SRST_)); - - if (unlikely(temp & HW_CFG_SRST_)) { - printk_err("Failed to complete reset"); - return -ENODEV; - } - - smsc911x_reg_write(0x00050000, pdata, HW_CFG); - smsc911x_reg_write(0x006E3740, pdata, AFC_CFG); - - /* Make sure EEPROM has finished loading before setting GPIO_CFG */ - timeout = 50; - while ((timeout--) && - (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_)) { - udelay(10); - } - - if (unlikely(timeout == 0)) { - SMSC_WARNING("Timed out waiting for EEPROM " - "busy bit to clear"); - } -#if USE_DEBUG >= 1 - smsc911x_reg_write(0x00670700, pdata, GPIO_CFG); -#else - smsc911x_reg_write(0x70070000, pdata, GPIO_CFG); -#endif - - /* Initialise irqs, but leave all sources disabled */ - smsc911x_reg_write(0, pdata, INT_EN); - smsc911x_reg_write(0xFFFFFFFF, pdata, INT_STS); - - /* Set interrupt deassertion to 100uS */ - //intcfg = ((0x38 << 24) | INT_CFG_IRQ_EN_); - intcfg = ((0x00 << 24) | INT_CFG_IRQ_EN_); - // PPH modified intcfg = ((10 << 24) | INT_CFG_IRQ_EN_); - - if (pdata->irq_polarity) { - SMSC_TRACE("irq polarity: active high"); - intcfg |= INT_CFG_IRQ_POL_; - } else { - SMSC_TRACE("irq polarity: active low"); - } - - if (pdata->irq_type) { - SMSC_TRACE("irq type: push-pull"); - intcfg |= INT_CFG_IRQ_TYPE_; - } else { - SMSC_TRACE("irq type: open drain"); - } - - smsc911x_reg_write(intcfg, pdata, INT_CFG); - - printk_debug("Testing irq handler using IRQ %d\n", dev->irq); - pdata->software_irq_signal = 0; - smp_wmb(); - - temp = smsc911x_reg_read(pdata, INT_EN); - temp |= INT_EN_SW_INT_EN_; - smsc911x_reg_write(temp, pdata, INT_EN); - - timeout = 1000; - while (timeout--) { - smp_rmb(); - if (pdata->software_irq_signal) - break; - msleep(1); - } - - if (!pdata->software_irq_signal) { - printk(KERN_WARNING "%s: ISR failed signaling test (IRQ %d)\n", - dev->name, dev->irq); - return -ENODEV; - } - - printk_debug("IRQ handler passed test using IRQ %d\n", dev->irq); - netif_carrier_off(dev); - - if (!smsc911x_phy_initialise(dev)) { - printk_err("Failed to initialize the PHY"); - return -ENODEV; - } - - temp = smsc911x_reg_read(pdata, HW_CFG); - temp &= HW_CFG_TX_FIF_SZ_; - temp |= HW_CFG_SF_; - smsc911x_reg_write(temp, pdata, HW_CFG); - - temp = smsc911x_reg_read(pdata, FIFO_INT); - temp |= FIFO_INT_TX_AVAIL_LEVEL_; - temp &= ~(FIFO_INT_RX_STS_LEVEL_); - smsc911x_reg_write(temp, pdata, FIFO_INT); - - /* set RX Data offset to 2 bytes for alignment */ - smsc911x_reg_write((2 << 8), pdata, RX_CFG); - - /* enable the polling before enabling the interrupts */ - napi_enable(&pdata->napi); - - temp = smsc911x_reg_read(pdata, INT_EN); - temp |= (INT_EN_TDFA_EN_ | INT_EN_RSFL_EN_ | INT_EN_RDFL_EN_); - smsc911x_reg_write(temp, pdata, INT_EN); - - spin_lock_irq(&pdata->phy_lock); - - /* - * Reenable the full duplex mode, otherwise the TX engine will generate - * status errors (Luis Galdos) - */ - temp = smsc911x_mac_read(pdata, MAC_CR); - temp |= (MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_ | MAC_CR_FDPX_); - smsc911x_mac_write(pdata, MAC_CR, temp); - spin_unlock_irq(&pdata->phy_lock); - - smsc911x_reg_write(TX_CFG_TX_ON_, pdata, TX_CFG); - - /* Set the MAC once again */ - memcpy(addr.sa_data, dev->dev_addr, dev->addr_len); - if(smsc911x_set_mac(dev, &addr)) - printk_err("Couldn't set the MAC address.\n"); - - netif_start_queue(dev); - return 0; -} - -/* Entry point for stopping the interface */ -static int smsc911x_stop(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - - printk_info("Stopping the interface\n"); - - napi_disable(&pdata->napi); - - /* disable interrupts */ - smsc911x_reg_write(0, pdata, INT_EN); - - pdata->stop_link_poll = 1; - del_timer_sync(&pdata->link_poll_timer); - - netif_stop_queue(dev); - - /* At this point all Rx and Tx activity is stopped */ - dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP); - smsc911x_tx_update_txcounters(pdata); - - /* Stop sending data after the last transmission */ - smsc911x_reg_write(TX_CFG_STOP_TX_, pdata, TX_CFG); - - SMSC_TRACE("Interface stopped"); - return 0; -} - -/* Entry point for transmitting a packet */ -static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned int freespace; - unsigned int tx_cmd_a; - unsigned int tx_cmd_b; - unsigned int temp; - u32 wrsz; - u32 bufp; - - freespace = smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TDFREE_; - - if (unlikely(freespace < TX_FIFO_LOW_THRESHOLD)) - SMSC_WARNING("Tx data fifo low, space available: %d", - freespace); - - /* Word alignment adjustment */ - tx_cmd_a = ((((unsigned int)(skb->data)) & 0x03) << 16); - tx_cmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; - tx_cmd_a |= (unsigned int)skb->len; - - tx_cmd_b = ((unsigned int)skb->len) << 16; - tx_cmd_b |= (unsigned int)skb->len; - - smsc911x_reg_write(tx_cmd_a, pdata, TX_DATA_FIFO); - smsc911x_reg_write(tx_cmd_b, pdata, TX_DATA_FIFO); - - bufp = ((u32)skb->data) & 0xFFFFFFFC; - wrsz = (u32)skb->len + 3; - wrsz += ((u32)skb->data) & 0x3; - wrsz >>= 2; - - smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); - freespace -= (skb->len + 32); - dev_kfree_skb(skb); - dev->trans_start = jiffies; - - if (unlikely(smsc911x_tx_get_txstatcount(pdata) >= 30)) - smsc911x_tx_update_txcounters(pdata); - - if (freespace < TX_FIFO_LOW_THRESHOLD) { - netif_stop_queue(dev); - temp = smsc911x_reg_read(pdata, FIFO_INT); - temp &= 0x00FFFFFF; - temp |= 0x32000000; - smsc911x_reg_write(temp, pdata, FIFO_INT); - } - - return NETDEV_TX_OK; -} - -/* Entry point for getting status counters */ -static struct net_device_stats *smsc911x_get_stats(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - smsc911x_tx_update_txcounters(pdata); - dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP); - return &dev->stats; -} - -/* Entry point for setting addressing modes */ -static void smsc911x_set_multicast_list(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned long flags; - - if (dev->flags & IFF_PROMISC) { - /* Enabling promiscuous mode */ - pdata->set_bits_mask = MAC_CR_PRMS_; - pdata->clear_bits_mask = (MAC_CR_MCPAS_ | MAC_CR_HPFILT_); - pdata->hashhi = 0; - pdata->hashlo = 0; - } else if (dev->flags & IFF_ALLMULTI) { - /* Enabling all multicast mode */ - pdata->set_bits_mask = MAC_CR_MCPAS_; - pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_HPFILT_); - pdata->hashhi = 0; - pdata->hashlo = 0; - } else if (dev->mc_count > 0) { - /* Enabling specific multicast addresses */ - unsigned int hash_high = 0; - unsigned int hash_low = 0; - unsigned int count = 0; - struct dev_mc_list *mc_list = dev->mc_list; - - pdata->set_bits_mask = MAC_CR_HPFILT_; - pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_); - - while (mc_list) { - count++; - if ((mc_list->dmi_addrlen) == ETH_ALEN) { - unsigned int bitnum = - smsc911x_hash(mc_list->dmi_addr); - unsigned int mask = 0x01 << (bitnum & 0x1F); - if (bitnum & 0x20) - hash_high |= mask; - else - hash_low |= mask; - } else { - SMSC_WARNING("dmi_addrlen != 6"); - } - mc_list = mc_list->next; - } - if (count != (unsigned int)dev->mc_count) - SMSC_WARNING("mc_count != dev->mc_count"); - - pdata->hashhi = hash_high; - pdata->hashlo = hash_low; - } else { - /* Enabling local MAC address only */ - pdata->set_bits_mask = 0; - pdata->clear_bits_mask = - (MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_); - pdata->hashhi = 0; - pdata->hashlo = 0; - } - - spin_lock_irqsave(&pdata->phy_lock, flags); - - if (pdata->generation <= 1) { - /* Older hardware revision - cannot change these flags while - * receiving data */ - if (!pdata->multicast_update_pending) { - unsigned int temp; - SMSC_TRACE("scheduling mcast update"); - pdata->multicast_update_pending = 1; - - /* Request the hardware to stop, then perform the - * update when we get an RX_STOP interrupt */ - smsc911x_reg_write(INT_STS_RXSTOP_INT_, pdata, INT_STS); - temp = smsc911x_reg_read(pdata, INT_EN); - temp |= INT_EN_RXSTOP_INT_EN_; - smsc911x_reg_write(temp, pdata, INT_EN); - - temp = smsc911x_mac_read(pdata, MAC_CR); - temp &= ~(MAC_CR_RXEN_); - smsc911x_mac_write(pdata, MAC_CR, temp); - } else { - /* There is another update pending, this should now - * use the newer values */ - } - } else { - /* Newer hardware revision - can write immediately */ - smsc911x_rx_multicast_update(pdata); - } - - spin_unlock_irqrestore(&pdata->phy_lock, flags); -} - -static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned int intsts; - unsigned int inten; - unsigned int temp; - unsigned int intcfg; - int serviced = IRQ_NONE; - - intcfg = smsc911x_reg_read(pdata, INT_CFG); - intsts = smsc911x_reg_read(pdata, INT_STS); - inten = smsc911x_reg_read(pdata, INT_EN); - - printk_debug("New IRQ: intsts 0x%08x\n", intsts); - - if ((intcfg & (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) != (INT_CFG_IRQ_INT_ | - INT_CFG_IRQ_EN_)) - return serviced; - - - if (unlikely(intsts & inten & INT_STS_SW_INT_)) { - temp = smsc911x_reg_read(pdata, INT_EN); - temp &= (~INT_EN_SW_INT_EN_); - smsc911x_reg_write(temp, pdata, INT_EN); - smsc911x_reg_write(INT_STS_SW_INT_, pdata, INT_STS); - pdata->software_irq_signal = 1; - smp_wmb(); - serviced = IRQ_HANDLED; - } - - if (unlikely(intsts & inten & INT_STS_RXSTOP_INT_)) { - /* Called when there is a multicast update scheduled and - * it is now safe to complete the update */ - SMSC_TRACE("RX Stop interrupt"); - temp = smsc911x_reg_read(pdata, INT_EN); - temp &= (~INT_EN_RXSTOP_INT_EN_); - smsc911x_reg_write(temp, pdata, INT_EN); - smsc911x_reg_write(INT_STS_RXSTOP_INT_, pdata, INT_STS); - smsc911x_rx_multicast_update_workaround(pdata); - serviced = IRQ_HANDLED; - } - - if (intsts & inten & INT_STS_TDFA_) { - temp = smsc911x_reg_read(pdata, FIFO_INT); - temp |= FIFO_INT_TX_AVAIL_LEVEL_; - smsc911x_reg_write(temp, pdata, FIFO_INT); - smsc911x_reg_write(INT_STS_TDFA_, pdata, INT_STS); - netif_wake_queue(dev); - serviced = IRQ_HANDLED; - } - - if (unlikely(intsts & inten & INT_STS_RXE_)) { - smsc911x_reg_write(INT_STS_RXE_, pdata, INT_STS); - serviced = IRQ_HANDLED; - } - - if (likely(intsts & inten & INT_STS_RSFL_)) { - if (likely(napi_schedule_prep(&pdata->napi))) { - /* Disable Rx interrupts and schedule NAPI poll */ - temp = smsc911x_reg_read(pdata, INT_EN); - temp &= (~INT_EN_RSFL_EN_); - smsc911x_reg_write(temp, pdata, INT_EN); - __napi_schedule(&pdata->napi); - } - - serviced = IRQ_HANDLED; - } - - if (unlikely(intsts & inten & INT_STS_PHY_INT_)) { - smsc911x_reg_write(INT_STS_PHY_INT_, pdata, INT_STS); - spin_lock(&pdata->phy_lock); - temp = smsc911x_phy_read(pdata, MII_INTSTS); - spin_unlock(&pdata->phy_lock); - SMSC_TRACE("PHY interrupt, sts 0x%04X", (u16)temp); - smsc911x_phy_update_linkmode(dev, 0); - serviced = IRQ_HANDLED; - } - return serviced; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -void smsc911x_poll_controller(struct net_device *dev) -{ - disable_irq(dev->irq); - smsc911x_irqhandler(0, dev); - enable_irq(dev->irq); -} -#endif /* CONFIG_NET_POLL_CONTROLLER */ - -/* Standard ioctls for mii-tool */ -static int smsc911x_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned int chg_in_duplex; - int ret; - - if (!netif_running(dev)) - return -EINVAL; - ret = generic_mii_ioctl(&pdata->mii, if_mii(ifr), cmd, &chg_in_duplex); - if ((ret == 0) && (chg_in_duplex != 0)) - smsc911x_phy_update_duplex(dev); - - return ret; -} - -static int -smsc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - - cmd->maxtxpkt = 1; - cmd->maxrxpkt = 1; - return mii_ethtool_gset(&pdata->mii, cmd); -} - -static int -smsc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - - return mii_ethtool_sset(&pdata->mii, cmd); -} - -static void smsc911x_ethtool_getdrvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - strlcpy(info->driver, SMSC_CHIPNAME, sizeof(info->driver)); - strlcpy(info->version, SMSC_DRV_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, dev_name(dev->dev.parent), - sizeof(info->bus_info)); -} - -static int smsc911x_ethtool_nwayreset(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - - return mii_nway_restart(&pdata->mii); -} - -static u32 smsc911x_ethtool_getmsglevel(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - return pdata->msg_enable; -} - -static void smsc911x_ethtool_setmsglevel(struct net_device *dev, u32 level) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - pdata->msg_enable = level; -} - -static int smsc911x_ethtool_getregslen(struct net_device *dev) -{ - return (((E2P_CMD - ID_REV) / 4 + 1) + (WUCSR - MAC_CR) + 1 + 32) * - sizeof(u32); -} - -static void -smsc911x_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs, - void *buf) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - unsigned long flags; - unsigned int i; - unsigned int j = 0; - u32 *data = buf; - - regs->version = pdata->idrev; - for (i = ID_REV; i <= E2P_CMD; i += (sizeof(u32))) - data[j++] = smsc911x_reg_read(pdata, i); - - spin_lock_irqsave(&pdata->phy_lock, flags); - for (i = MAC_CR; i <= WUCSR; i++) - data[j++] = smsc911x_mac_read(pdata, i); - for (i = 0; i <= 31; i++) - data[j++] = smsc911x_phy_read(pdata, i); - spin_unlock_irqrestore(&pdata->phy_lock, flags); -} - -static void smsc911x_eeprom_enable_access(struct smsc911x_data *pdata) -{ - unsigned int temp = smsc911x_reg_read(pdata, GPIO_CFG); - temp &= ~GPIO_CFG_EEPR_EN_; - smsc911x_reg_write(temp, pdata, GPIO_CFG); - msleep(1); -} - -static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op) -{ - int timeout = 100; - u32 e2cmd; - - SMSC_TRACE("op 0x%08x", op); - if (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) { - SMSC_WARNING("Busy at start"); - return -EBUSY; - } - - e2cmd = op | E2P_CMD_EPC_BUSY_; - smsc911x_reg_write(e2cmd, pdata, E2P_CMD); - - do { - msleep(1); - e2cmd = smsc911x_reg_read(pdata, E2P_CMD); - } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (timeout--)); - - if (!timeout) { - SMSC_TRACE("TIMED OUT"); - return -EAGAIN; - } - - if (e2cmd & E2P_CMD_EPC_TIMEOUT_) { - SMSC_TRACE("Error occured during eeprom operation"); - return -EINVAL; - } - - return 0; -} - -static int smsc911x_eeprom_read_location(struct smsc911x_data *pdata, - u8 address, u8 *data) -{ - u32 op = E2P_CMD_EPC_CMD_READ_ | address; - int ret; - - SMSC_TRACE("address 0x%x", address); - ret = smsc911x_eeprom_send_cmd(pdata, op); - - if (!ret) - data[address] = smsc911x_reg_read(pdata, E2P_DATA); - - return ret; -} - -static int smsc911x_eeprom_write_location(struct smsc911x_data *pdata, - u8 address, u8 data) -{ - u32 op = E2P_CMD_EPC_CMD_ERASE_ | address; - int ret; - - SMSC_TRACE("address 0x%x, data 0x%x", address, data); - ret = smsc911x_eeprom_send_cmd(pdata, op); - - if (!ret) { - op = E2P_CMD_EPC_CMD_WRITE_ | address; - smsc911x_reg_write((u32)data, pdata, E2P_DATA); - ret = smsc911x_eeprom_send_cmd(pdata, op); - } - - return ret; -} - -static int smsc911x_ethtool_get_eeprom_len(struct net_device *dev) -{ - return SMSC911X_EEPROM_SIZE; -} - -static int smsc911x_ethtool_get_eeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *data) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - u8 eeprom_data[SMSC911X_EEPROM_SIZE]; - int len; - int i; - - smsc911x_eeprom_enable_access(pdata); - - len = min(eeprom->len, SMSC911X_EEPROM_SIZE); - for (i = 0; i < len; i++) { - int ret = smsc911x_eeprom_read_location(pdata, i, eeprom_data); - if (ret < 0) { - eeprom->len = 0; - return ret; - } - } - - memcpy(data, &eeprom_data[eeprom->offset], len); - eeprom->len = len; - return 0; -} - -static int smsc911x_ethtool_set_eeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 *data) -{ - int ret; - struct smsc911x_data *pdata = netdev_priv(dev); - - smsc911x_eeprom_enable_access(pdata); - smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWEN_); - ret = smsc911x_eeprom_write_location(pdata, eeprom->offset, *data); - smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWDS_); - - /* Single byte write, according to man page */ - eeprom->len = 1; - - return ret; -} - -static int smsc911x_ethtool_set_wol(struct net_device *dev, - struct ethtool_wolinfo *wol) -{ - struct smsc911x_data *pdata; - - /* Check for unsupported options */ - if (wol->wolopts & (WAKE_MAGICSECURE | WAKE_UCAST | WAKE_MCAST - | WAKE_BCAST | WAKE_ARP)) - return -EINVAL; - - pdata = netdev_priv(dev); - - /* When disable the WOL options need to disable the PHY-interrupts too */ - if (!wol->wolopts) { - printk_pmdbg("[ WOL ] Disabling all sources\n"); - pdata->pmt_ctrl &= ~(PMT_CTRL_WOL_EN_ | PMT_CTRL_ED_EN_); - pdata->phy_intmsk &= ~PHY_INTMSK_ENERGYON_; - pdata->mac_wucsr = 0; - goto exit_set_wol; - } - - /* - * For the magic packet we MUST configure the MAC too, but we can't do it - * at this point, cause the controller stops working. - */ - if (wol->wolopts & WAKE_MAGIC) { - printk_pmdbg("WOL: Enabling magic frame\n"); - pdata->mac_wucsr |= WUCSR_MPEN_; - pdata->pmt_ctrl |= PMT_CTRL_WOL_EN_; - } - - /* For the PHY-wakeup we must use the energy detection */ - if (wol->wolopts & WAKE_PHY) { - printk_pmdbg("[ WOL ] Enabling PHY energy\n"); - pdata->phy_intmsk |= PHY_INTMSK_ENERGYON_; - pdata->pmt_ctrl |= PMT_CTRL_ED_EN_; - } - - exit_set_wol: - return 0; -} - -/* Function for getting the infos about the WOL */ -static void smsc911x_ethtool_get_wol(struct net_device *net_dev, - struct ethtool_wolinfo *wol) -{ - /* Only for magic and PHY power detection available up now */ - wol->supported = WAKE_MAGIC | WAKE_PHY; -} - -static struct ethtool_ops smsc911x_ethtool_ops = { - .get_settings = smsc911x_ethtool_getsettings, - .set_settings = smsc911x_ethtool_setsettings, - .get_link = ethtool_op_get_link, - .get_drvinfo = smsc911x_ethtool_getdrvinfo, - .nway_reset = smsc911x_ethtool_nwayreset, - .get_msglevel = smsc911x_ethtool_getmsglevel, - .set_msglevel = smsc911x_ethtool_setmsglevel, - .get_regs_len = smsc911x_ethtool_getregslen, - .get_regs = smsc911x_ethtool_getregs, - .get_eeprom_len = smsc911x_ethtool_get_eeprom_len, - .get_eeprom = smsc911x_ethtool_get_eeprom, - .set_eeprom = smsc911x_ethtool_set_eeprom, - .get_wol = smsc911x_ethtool_get_wol, - .set_wol = smsc911x_ethtool_set_wol, -}; - - -static int smsc911x_set_mac(struct net_device *dev, void *addr) -{ - unsigned int reg; - int retval; - unsigned long flags; - struct smsc911x_data *pdata; - unsigned int low, high; - struct sockaddr *paddr = addr; - - printk_debug("Set mac called\n"); - - pdata = netdev_priv(dev); - - spin_lock_irqsave(&pdata->phy_lock, flags); - - /* First check that the MAC is not busy */ - reg = smsc911x_reg_read(pdata, MAC_CSR_CMD); - if (unlikely(reg & MAC_CSR_CMD_CSR_BUSY_)) { - printk_err("smsc911x_mac_read failed, MAC busy at entry"); - retval = -EBUSY; - goto exit_unlock; - } - - /* Get the MAC address */ - high = 0; - memcpy(&low, &(paddr->sa_data[0]), 4); - memcpy(&high, &(paddr->sa_data[4]), 2); - printk_debug("Going to set the MAC %04X%08X\n", high, low); - - /* Now set the high address */ - smsc911x_reg_write(high, pdata, MAC_CSR_DATA); - smsc911x_reg_write(ADDRH | MAC_CSR_CMD_CSR_BUSY_, pdata, MAC_CSR_CMD); - reg = smsc911x_reg_read(pdata, BYTE_TEST); - if (!smsc911x_mac_notbusy(pdata)) { - retval = -EBUSY; - goto exit_unlock; - } - - /* First set the low address */ - smsc911x_reg_write(low, pdata, MAC_CSR_DATA); - smsc911x_reg_write(ADDRL | MAC_CSR_CMD_CSR_BUSY_, pdata, MAC_CSR_CMD); - reg = smsc911x_reg_read(pdata, BYTE_TEST); - if (!smsc911x_mac_notbusy(pdata)) { - retval = -EBUSY; - goto exit_unlock; - } - - /* And save the IP inside the driver structure */ - memcpy(dev->dev_addr, paddr->sa_data, dev->addr_len); - - printk_debug("MAC successful changed to %02X%08X\n", - smsc911x_mac_read(pdata, ADDRH), - smsc911x_mac_read(pdata, ADDRL)); - - retval = 0; - - exit_unlock: - spin_unlock_irqrestore(&pdata->phy_lock, flags); - - return retval; -} - -static const struct net_device_ops smsc911x_netdev_ops = { - .ndo_open = smsc911x_open, - .ndo_stop = smsc911x_stop, - .ndo_start_xmit = smsc911x_hard_start_xmit, - .ndo_get_stats = smsc911x_get_stats, - .ndo_set_multicast_list = smsc911x_set_multicast_list, - .ndo_do_ioctl = smsc911x_do_ioctl, - .ndo_set_mac_address = smsc911x_set_mac, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = smsc911x_poll_controller, -#endif -}; - -/* Initializing private device structures */ -static int smsc911x_init(struct net_device *dev) -{ - struct smsc911x_data *pdata = netdev_priv(dev); - - SMSC_TRACE("Driver Parameters:"); - SMSC_TRACE("LAN base: 0x%08lX", (unsigned long)pdata->ioaddr); - SMSC_TRACE("IRQ: %d", dev->irq); - SMSC_TRACE("PHY will be autodetected."); - - if (pdata->ioaddr == 0) { - SMSC_WARNING("pdata->ioaddr: 0x00000000"); - return -ENODEV; - } - - /* Default generation to zero (all workarounds apply) */ - pdata->generation = 0; - - pdata->idrev = smsc911x_reg_read(pdata, ID_REV); - if (((pdata->idrev >> 16) & 0xFFFF) == (pdata->idrev & 0xFFFF)) { - SMSC_WARNING("idrev top 16 bits equal to bottom 16 bits, " - "idrev: 0x%08X", pdata->idrev); - SMSC_TRACE("This may mean the chip is set for 32 bit while " - "the bus is reading as 16 bit"); - return -ENODEV; - } - switch (pdata->idrev & 0xFFFF0000) { - case 0x01180000: - switch (pdata->idrev & 0x0000FFFFUL) { - case 0UL: - SMSC_TRACE("LAN9118 Beacon identified, idrev: 0x%08X", - pdata->idrev); - pdata->generation = 0; - break; - case 1UL: - SMSC_TRACE - ("LAN9118 Concord A0 identified, idrev: 0x%08X", - pdata->idrev); - pdata->generation = 1; - break; - case 2UL: - SMSC_TRACE - ("LAN9118 Concord A1 identified, idrev: 0x%08X", - pdata->idrev); - pdata->generation = 2; - break; - default: - SMSC_TRACE - ("LAN9118 Concord A1 identified (NEW), idrev: 0x%08X", - pdata->idrev); - pdata->generation = 2; - break; - } - break; - - case 0x01170000: - switch (pdata->idrev & 0x0000FFFFUL) { - case 0UL: - SMSC_TRACE("LAN9117 Beacon identified, idrev: 0x%08X", - pdata->idrev); - pdata->generation = 0; - break; - case 1UL: - SMSC_TRACE - ("LAN9117 Concord A0 identified, idrev: 0x%08X", - pdata->idrev); - pdata->generation = 1; - break; - case 2UL: - SMSC_TRACE - ("LAN9117 Concord A1 identified, idrev: 0x%08X", - pdata->idrev); - pdata->generation = 2; - break; - default: - SMSC_TRACE - ("LAN9117 Concord A1 identified (NEW), idrev: 0x%08X", - pdata->idrev); - pdata->generation = 2; - break; - } - break; - - case 0x01160000: - switch (pdata->idrev & 0x0000FFFFUL) { - case 0UL: - SMSC_WARNING("LAN911x not identified, idrev: 0x%08X", - pdata->idrev); - return -ENODEV; - case 1UL: - SMSC_TRACE - ("LAN9116 Concord A0 identified, idrev: 0x%08X", - pdata->idrev); - pdata->generation = 1; - break; - case 2UL: - SMSC_TRACE - ("LAN9116 Concord A1 identified, idrev: 0x%08X", - pdata->idrev); - pdata->generation = 2; - break; - default: - SMSC_TRACE - ("LAN9116 Concord A1 identified (NEW), idrev: 0x%08X", - pdata->idrev); - pdata->generation = 2; - break; - } - break; - - case 0x01150000: - switch (pdata->idrev & 0x0000FFFFUL) { - case 0UL: - SMSC_WARNING("LAN911x not identified, idrev: 0x%08X", - pdata->idrev); - return -ENODEV; - case 1UL: - SMSC_TRACE - ("LAN9115 Concord A0 identified, idrev: 0x%08X", - pdata->idrev); - pdata->generation = 1; - break; - case 2UL: - SMSC_TRACE - ("LAN9115 Concord A1 identified, idrev: 0x%08X", - pdata->idrev); - pdata->generation = 2; - break; - default: - SMSC_TRACE - ("LAN9115 Concord A1 identified (NEW), idrev: 0x%08X", - pdata->idrev); - pdata->generation = 2; - break; - } - break; - - case 0x118A0000UL: - switch (pdata->idrev & 0x0000FFFFUL) { - case 0UL: - SMSC_TRACE - ("LAN9218 Boylston identified, idrev: 0x%08X", - pdata->idrev); - pdata->generation = 3; - break; - default: - SMSC_TRACE - ("LAN9218 Boylston identified (NEW), idrev: 0x%08X", - pdata->idrev); - pdata->generation = 3; - break; - } - break; - - case 0x117A0000UL: - switch (pdata->idrev & 0x0000FFFFUL) { - case 0UL: - SMSC_TRACE - ("LAN9217 Boylston identified, idrev: 0x%08X", - pdata->idrev); - pdata->generation = 3; - break; - default: - SMSC_TRACE - ("LAN9217 Boylston identified (NEW), idrev: 0x%08X", - pdata->idrev); - pdata->generation = 3; - break; - } - break; - - case 0x116A0000UL: - switch (pdata->idrev & 0x0000FFFFUL) { - case 0UL: - SMSC_TRACE - ("LAN9216 Boylston identified, idrev: 0x%08X", - pdata->idrev); - pdata->generation = 3; - break; - default: - SMSC_TRACE - ("LAN9216 Boylston identified (NEW), idrev: 0x%08X", - pdata->idrev); - pdata->generation = 3; - break; - } - break; - - case 0x115A0000UL: - switch (pdata->idrev & 0x0000FFFFUL) { - case 0UL: - SMSC_TRACE - ("LAN9215 Boylston identified, idrev: 0x%08X", - pdata->idrev); - pdata->generation = 3; - break; - default: - SMSC_TRACE - ("LAN9215 Boylston identified (NEW), idrev: 0x%08X", - pdata->idrev); - pdata->generation = 3; - break; - } - break; - - case 0x92100000UL: - case 0x92110000UL: - case 0x92200000UL: - case 0x92210000UL: - /* LAN9210/LAN9211/LAN9220/LAN9221 */ - pdata->generation = 4; - break; - - default: - SMSC_WARNING("LAN911x not identified, idrev: 0x%08X", - pdata->idrev); - return -ENODEV; - } - - if (pdata->generation == 0) - SMSC_WARNING("This driver is not intended " - "for this chip revision"); - - ether_setup(dev); - dev->flags |= IFF_MULTICAST; - netif_napi_add(dev, &pdata->napi, smsc911x_poll, 64);//SMSC_NAPI_WEIGHT - dev->netdev_ops = &smsc911x_netdev_ops; - dev->ethtool_ops = &smsc911x_ethtool_ops; - - pdata->mii.phy_id_mask = 0x1f; - pdata->mii.reg_num_mask = 0x1f; - pdata->mii.force_media = 0; - pdata->mii.full_duplex = 0; - pdata->mii.dev = dev; - pdata->mii.mdio_read = smsc911x_mdio_read; - pdata->mii.mdio_write = smsc911x_mdio_write; - - pdata->msg_enable = NETIF_MSG_LINK; - - return 0; -} - -static int smsc911x_drv_remove(struct platform_device *pdev) -{ - struct net_device *dev; - struct smsc911x_data *pdata; - struct resource *res; - - dev = platform_get_drvdata(pdev); - BUG_ON(!dev); - pdata = netdev_priv(dev); - BUG_ON(!pdata); - BUG_ON(!pdata->ioaddr); - - SMSC_TRACE("Stopping driver."); - platform_set_drvdata(pdev, NULL); - unregister_netdev(dev); - free_irq(dev->irq, dev); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "smsc911x-memory"); - if (!res) - platform_get_resource(pdev, IORESOURCE_MEM, 0); - - release_mem_region(res->start, res->end - res->start); - - iounmap(pdata->ioaddr); - - free_netdev(dev); - - return 0; -} - -static int smsc911x_drv_probe(struct platform_device *pdev) -{ - struct net_device *dev; - struct smsc911x_data *pdata; - struct resource *res; - unsigned int intcfg = 0; - int res_size; - int retval; - - printk(KERN_INFO "%s: Driver version %s.\n", SMSC_CHIPNAME, - SMSC_DRV_VERSION); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "smsc911x-memory"); - if (!res) - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - printk(KERN_WARNING "%s: Could not allocate resource.\n", - SMSC_CHIPNAME); - retval = -ENODEV; - goto out_0; - } - res_size = res->end - res->start; - - if (!request_mem_region(res->start, res_size, SMSC_CHIPNAME)) { - retval = -EBUSY; - goto out_0; - } - - dev = alloc_etherdev(sizeof(struct smsc911x_data)); - if (!dev) { - printk(KERN_WARNING "%s: Could not allocate device.\n", - SMSC_CHIPNAME); - retval = -ENOMEM; - goto out_release_io_1; - } - - SET_NETDEV_DEV(dev, &pdev->dev); - - pdata = netdev_priv(dev); - pdata->netdev = dev; - - dev->irq = platform_get_irq(pdev, 0); - pdata->ioaddr = ioremap_nocache(res->start, res_size); - - /* copy config parameters across if present, otherwise pdata - * defaults to zeros */ - if (pdev->dev.platform_data) { - struct smc911x_platdata *config = pdev->dev.platform_data; - pdata->irq_polarity = config->irq_polarity; - pdata->irq_flags = config->irq_flags; - pdata->irq_type = config->irq_type; - } - - if (pdata->ioaddr == NULL) { - SMSC_WARNING("Error smsc911x base address invalid"); - retval = -ENOMEM; - goto out_free_netdev_2; - } - - retval = smsc911x_init(dev); - if (retval < 0) - goto out_unmap_io_3; - - /* configure irq polarity and type before connecting isr */ - if (pdata->irq_polarity) - intcfg |= INT_CFG_IRQ_POL_; - - if (pdata->irq_type) - intcfg |= INT_CFG_IRQ_TYPE_; - - smsc911x_reg_write(intcfg, pdata, INT_CFG); - - retval = request_irq(dev->irq, smsc911x_irqhandler, - pdata->irq_flags, - SMSC_CHIPNAME, dev); - if (retval) { - SMSC_WARNING("Unable to claim requested irq: %d", dev->irq); - goto out_unmap_io_3; - } - - platform_set_drvdata(pdev, dev); - - retval = register_netdev(dev); - if (retval) { - SMSC_WARNING("Error %i registering device", retval); - goto out_unset_drvdata_4; - } else { - SMSC_TRACE("Network interface: \"%s\"", dev->name); - } - - spin_lock_init(&pdata->phy_lock); - - spin_lock_irq(&pdata->phy_lock); - - /* Check if mac address has been specified when bringing interface up */ - if (is_valid_ether_addr(dev->dev_addr)) { - smsc911x_set_mac(dev, dev->dev_addr); - SMSC_TRACE("MAC Address is specified by configuration"); - } else { - /* Try reading mac address from device. if EEPROM is present - * it will already have been set */ - u32 mac_high16 = smsc911x_mac_read(pdata, ADDRH); - u32 mac_low32 = smsc911x_mac_read(pdata, ADDRL); - dev->dev_addr[0] = (u8)(mac_low32); - dev->dev_addr[1] = (u8)(mac_low32 >> 8); - dev->dev_addr[2] = (u8)(mac_low32 >> 16); - dev->dev_addr[3] = (u8)(mac_low32 >> 24); - dev->dev_addr[4] = (u8)(mac_high16); - dev->dev_addr[5] = (u8)(mac_high16 >> 8); - - if (is_valid_ether_addr(dev->dev_addr)) { - /* eeprom values are valid so use them */ - SMSC_TRACE("Mac Address is read from LAN911x EEPROM"); - } else { - /* eeprom values are invalid, generate random MAC */ - random_ether_addr(dev->dev_addr); - smsc911x_set_mac_address(pdata, dev->dev_addr); - SMSC_TRACE("MAC Address is set to random_ether_addr"); - } - } - - spin_unlock_irq(&pdata->phy_lock); - - printk_info("%s: MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); - - /* Enable the wakeup over this device (Luis Galdos) */ - device_init_wakeup(&pdev->dev, 1); - device_set_wakeup_enable(&pdev->dev, 0); - return 0; - -out_unset_drvdata_4: - platform_set_drvdata(pdev, NULL); - free_irq(dev->irq, dev); -out_unmap_io_3: - iounmap(pdata->ioaddr); -out_free_netdev_2: - free_netdev(dev); -out_release_io_1: - release_mem_region(res->start, res->end - res->start); -out_0: - return retval; -} - -/* Enter in the suspend mode */ -#if defined(CONFIG_PM) - -/* - * For the mode D1 we MUST left the interrupts enabled - */ -static int smsc911x_drv_state_wakeup(struct smsc911x_data *pdata, int mode) -{ - int retval; - unsigned long regval; - - retval = 0; - - if (mode != 1 && mode != 2) - return -EINVAL; - - /* Clear already received WUs */ - regval = smsc911x_mac_read(pdata, WUCSR); - regval &= ~(WUCSR_MPR_ | WUCSR_WUFR_); - regval |= pdata->mac_wucsr; /* Magic packet enable 'WUCSR_MPEN_' */ - printk_pmdbg("[ SUSP ] WUCSR 0x%08lx\n", regval); - smsc911x_mac_write(pdata, WUCSR, regval); - - /* For the D2 we must enable the PHY interrupt for the energy detection */ - regval = smsc911x_reg_read(pdata, INT_EN); - regval |= (INT_EN_PME_INT_EN_ | INT_EN_PHY_INT_EN_); - printk_pmdbg("[ SUSP ] INT_EN 0x%08lx\n", regval); - smsc911x_reg_write(regval, pdata, INT_EN); - - if (mode /* @FIXME: Enabled only for D2 */) { - u16 phy_mode; - - phy_mode = smsc911x_phy_read(pdata, MII_INTMSK); - phy_mode |= PHY_INTMSK_ENERGYON_; - smsc911x_phy_write(pdata, MII_INTMSK, phy_mode); - } - - /* Clear the PM mode and clear the current wakeup status */ - regval = smsc911x_reg_read(pdata, PMT_CTRL); - regval &= ~PMT_CTRL_PM_MODE_; - regval |= PMT_CTRL_WUPS_; - printk_pmdbg("[ SUSP ] PMT_CTRL 0x%08lx\n", regval); - smsc911x_reg_write(regval, pdata, PMT_CTRL); - - /* Enable the PME at prior and the wake on LAN */ - regval = smsc911x_reg_read(pdata, PMT_CTRL); - regval |= pdata->pmt_ctrl; /* Enable the ENERGY detect or WOL interrupt */ - regval |= PMT_CTRL_PME_EN_; - - if (mode == 1) - regval |= PMT_CTRL_PM_MODE_D1_; - else - regval |= PMT_CTRL_PM_MODE_D2_; - - printk_pmdbg("[ SUSP ] PMT_CTRL 0x%08lx\n", regval); - smsc911x_reg_write(regval, pdata, PMT_CTRL); - - return retval; -} - -/* For the state D2 we must disable the host-interrupts */ -static int smsc911x_drv_state_d2(struct smsc911x_data *pdata) -{ - unsigned long regval; - - /* Disable the interrupts of the controller */ - regval = smsc911x_reg_read(pdata, INT_CFG); - regval &= ~INT_CFG_IRQ_EN_; - smsc911x_reg_write(regval, pdata, INT_CFG); - - /* Set the phy to the power down mode */ - regval = smsc911x_phy_read(pdata, MII_BMCR); - regval |= BMCR_PDOWN; - smsc911x_phy_write(pdata, MII_BMCR, regval); - - /* - * Enter into the power mode D2 (the controller doesn't - * support the mode D3) - */ - regval = smsc911x_reg_read(pdata, PMT_CTRL); - regval &= ~PMT_CTRL_PM_MODE_; - regval |= PMT_CTRL_PM_MODE_D2_; - smsc911x_reg_write(regval, pdata, PMT_CTRL); - - return 0; -} - -static int smsc911x_drv_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct net_device *ndev; - struct smsc911x_data *pdata; - int retval; - - ndev = platform_get_drvdata(pdev); - pdata = netdev_priv(ndev); - - if (!ndev) - return -ENODEV; - - /* @FIXME: Implement the other supported power modes of the smsc911x */ - if (state.event != PM_EVENT_SUSPEND) - return -ENOTSUPP; - - if (netif_running(ndev)) { - - /* The below code is coming from the WinCE guys */ - netif_device_detach(ndev); - - /* - * If configured as wakeup-source enter the mode D1 for packet - * detection using the standard IRQ-line - */ - if (device_may_wakeup(&pdev->dev)) { - - /* - * Sanity check for verifying that a wakeup-source was - * configured from the user space. If the energy-detect - * wakeup was enabled, then use the D2 for entering into the - * power mode - */ - if (!(pdata->pmt_ctrl & (PMT_CTRL_WOL_EN_ | PMT_CTRL_ED_EN_))) { - printk_err("[ SUSP ] No WOL source defined.\n"); - retval = -EINVAL; - goto err_attach; - } - - /* - * By the WOL (magic packet, etc.) we can ONLY use the D1, but - * for the energy detect over the PHY we can change into D2 - */ - if (pdata->pmt_ctrl & PMT_CTRL_WOL_EN_) { - printk_pmdbg("[ SUSP ] Preparing D1 with wakeup\n"); - smsc911x_drv_state_wakeup(pdata, 1); - } else { - /* @TEST: Use first only D1 for the wakups */ - printk_pmdbg("[ SUSP ] Preparing D2 with wakeup\n"); - smsc911x_drv_state_wakeup(pdata, 2); - } - - enable_irq_wake(ndev->irq); - - } else { - /* - * Enter into the power mode D2 (the controller doesn't - * support the mode D3) - */ - smsc911x_drv_state_d2(pdata); - } - } - - return 0; - -err_attach: - netif_device_attach(ndev); - return retval; -} - -static int smsc911x_drv_resume(struct platform_device *pdev) -{ - int retval; - struct net_device *ndev; - unsigned long pmt_ctrl; - - pmt_ctrl = 0; - ndev = platform_get_drvdata(pdev); - retval = 0; - if (ndev) { - struct smsc911x_data *pdata = netdev_priv(ndev); - - if (netif_running(ndev)) { - unsigned long timeout; - unsigned long regval, pmt_ctrl; - - /* Assert the byte test register for waking up */ - smsc911x_reg_write(0x0, pdata, BYTE_TEST); - - timeout = 100000; - do { - timeout--; - regval = smsc911x_reg_read(pdata, PMT_CTRL); - udelay(1); - } while (timeout && !(regval & PMT_CTRL_READY_)); - - if (!timeout) { - printk_err("Wakeup timeout by the controller\n"); - retval = -EBUSY; - goto exit_resume; - } - - /* - * Check if we received a PM interrupt - * Please take note that we are supporting ONLY the Wake On LAN - * interrupts, and not the energy-on - * (Luis Galdos) - */ - pmt_ctrl = smsc911x_reg_read(pdata, PMT_CTRL); - regval = smsc911x_reg_read(pdata, INT_STS); - printk_pmdbg("[ WAKE ] PMT_CTRL 0x%08lx\n", pmt_ctrl); - printk_pmdbg("[ WAKE ] INT_STS 0x%08lx\n", regval); - if (regval & (INT_STS_PME_INT_ | INT_STS_PHY_INT_)) { - - /* Disable the power management interrupts */ - regval = smsc911x_reg_read(pdata, PMT_CTRL); - pmt_ctrl = regval & (PMT_CTRL_WOL_EN_ | PMT_CTRL_ED_EN_); - regval &= ~(PMT_CTRL_WOL_EN_ | PMT_CTRL_PME_EN_ | - PMT_CTRL_ED_EN_); - smsc911x_reg_write(regval, pdata, PMT_CTRL); - - /* Disable the PM interrupts */ - regval = smsc911x_reg_read(pdata, INT_EN); - regval &= ~(INT_EN_PME_INT_EN_ | INT_EN_PHY_INT_EN_); - smsc911x_reg_write(regval, pdata, INT_EN); - - /* Disable the wakeup-events on the MAC */ - regval = smsc911x_mac_read(pdata, WUCSR); - regval &= ~(WUCSR_MPEN_); - smsc911x_mac_write(pdata, WUCSR, regval); - } - - /* @XXX: Clear only the interrupts that were generated */ - regval = (INT_STS_PME_INT_ | INT_STS_PHY_INT_); - smsc911x_reg_write(regval, pdata, INT_STS); - - /* Set the controller into the state D0 */ - regval = smsc911x_reg_read(pdata, PMT_CTRL); - regval &= ~PMT_CTRL_PM_MODE_; - regval |= PMT_CTRL_PM_MODE_D0_; - smsc911x_reg_write(regval, pdata, PMT_CTRL); - - /* Paranoic sanity checks */ - regval = smsc911x_reg_read(pdata, PMT_CTRL); - if (regval & PMT_CTRL_PM_MODE_) - printk_err("PM mode isn't disabled (0x%04lx)\n", regval); - - if (!(regval & PMT_CTRL_READY_)) { - retval = -EBUSY; - printk_err("Device is still NOT ready.\n"); - goto exit_resume; - } - - regval = smsc911x_phy_read(pdata, MII_BMCR); - regval &= ~BMCR_PDOWN; - smsc911x_phy_write(pdata, MII_BMCR, regval); - - /* Reenable the interrupts now */ - regval = smsc911x_reg_read(pdata, INT_CFG); - regval |= INT_CFG_IRQ_EN_; - smsc911x_reg_write(regval, pdata, INT_CFG); - - /* Reset the wakeup control and status register */ - smsc911x_mac_write(pdata, WUCSR, 0x00); - - netif_device_attach(ndev); - } - } - -exit_resume: - return retval; -} -#else -#define smsc911x_drv_suspend NULL -#define smsc911x_drv_resume NULL -#endif /* defined(CONFIG_PM) */ - -static struct platform_driver smsc911x_driver = { - .probe = smsc911x_drv_probe, - .remove = smsc911x_drv_remove, - .suspend = smsc911x_drv_suspend, - .resume = smsc911x_drv_resume, - .driver = { - .name = SMSC_CHIPNAME, - }, -}; - -/* Entry point for loading the module */ -static int __init smsc911x_init_module(void) -{ - printk(KERN_INFO "SMSC 911X: Starting the platform driver.\n"); - return platform_driver_register(&smsc911x_driver); -} - -/* entry point for unloading the module */ -static void __exit smsc911x_cleanup_module(void) -{ - platform_driver_unregister(&smsc911x_driver); -} - -module_init(smsc911x_init_module); -module_exit(smsc911x_cleanup_module); diff --git a/drivers/net/smsc9118/smsc911x.h b/drivers/net/smsc9118/smsc911x.h deleted file mode 100644 index a2ee96aeb989..000000000000 --- a/drivers/net/smsc9118/smsc911x.h +++ /dev/null @@ -1,393 +0,0 @@ -/*************************************************************************** - * - * Copyright (C) 2004-2007 SMSC - * Copyright (C) 2005 ARM - * - * 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 __SMSC911X_H__ -#define __SMSC911X_H__ - -#if defined(CONFIG_MACH_CC9M2443JS) || defined(CONFIG_MACH_CCW9M2443JS) -# define SMSC_CAN_USE_32BIT 0 -#else -# define SMSC_CAN_USE_32BIT 1 -#endif - - -//#define SMSC_CAN_USE_32BIT 1 -#define TX_FIFO_LOW_THRESHOLD (u32)1600 -#define SMSC911X_EEPROM_SIZE (u32)7 -#define USE_DEBUG 0 -//#define USE_DEBUG 2 - -/* implements a PHY loopback test at initialisation time, to ensure a packet - * can be succesfully looped back */ -#define USE_PHY_WORK_AROUND - -/* 10/100 LED link-state inversion when media is disconnected */ -/* #define USE_LED1_WORK_AROUND */ - -/* platform_device configuration data, should be assigned to - * the platform_device's dev.platform_data */ -struct smsc911x_platform_config { - unsigned int irq_polarity; - unsigned int irq_type; -}; - -#if USE_DEBUG >= 1 -#define SMSC_WARNING(fmt, args...) \ - printk(KERN_EMERG "SMSC_WARNING: %s: " fmt "\n", \ - __FUNCTION__ , ## args) -#else -#define SMSC_WARNING(msg, args...) -#endif /* USE_DEBUG >= 1 */ - -#if USE_DEBUG >= 2 -#define SMSC_TRACE(fmt,args...) \ - printk(KERN_EMERG "SMSC_TRACE: %s: " fmt "\n", \ - __FUNCTION__ , ## args) -#else -#define SMSC_TRACE(msg, args...) -#endif /* USE_DEBUG >= 2 */ - -/* SMSC911x registers and bitfields */ -#define RX_DATA_FIFO 0x00 - -#define TX_DATA_FIFO 0x20 -#define TX_CMD_A_ON_COMP_ 0x80000000 -#define TX_CMD_A_BUF_END_ALGN_ 0x03000000 -#define TX_CMD_A_4_BYTE_ALGN_ 0x00000000 -#define TX_CMD_A_16_BYTE_ALGN_ 0x01000000 -#define TX_CMD_A_32_BYTE_ALGN_ 0x02000000 -#define TX_CMD_A_DATA_OFFSET_ 0x001F0000 -#define TX_CMD_A_FIRST_SEG_ 0x00002000 -#define TX_CMD_A_LAST_SEG_ 0x00001000 -#define TX_CMD_A_BUF_SIZE_ 0x000007FF -#define TX_CMD_B_PKT_TAG_ 0xFFFF0000 -#define TX_CMD_B_ADD_CRC_DISABLE_ 0x00002000 -#define TX_CMD_B_DISABLE_PADDING_ 0x00001000 -#define TX_CMD_B_PKT_BYTE_LENGTH_ 0x000007FF - -#define RX_STATUS_FIFO 0x40 -#define RX_STS_ES_ 0x00008000 -#define RX_STS_MCAST_ 0x00000400 - -#define RX_STATUS_FIFO_PEEK 0x44 - -#define TX_STATUS_FIFO 0x48 -#define TX_STS_ES_ 0x00008000 - -#define TX_STATUS_FIFO_PEEK 0x4C - -#define ID_REV 0x50 -#define ID_REV_CHIP_ID_ 0xFFFF0000 -#define ID_REV_REV_ID_ 0x0000FFFF - -#define INT_CFG 0x54 -#define INT_CFG_INT_DEAS_ 0xFF000000 -#define INT_CFG_INT_DEAS_CLR_ 0x00004000 -#define INT_CFG_INT_DEAS_STS_ 0x00002000 -#define INT_CFG_IRQ_INT_ 0x00001000 -#define INT_CFG_IRQ_EN_ 0x00000100 -#define INT_CFG_IRQ_POL_ 0x00000010 -#define INT_CFG_IRQ_TYPE_ 0x00000001 - -#define INT_STS 0x58 -#define INT_STS_SW_INT_ 0x80000000 -#define INT_STS_TXSTOP_INT_ 0x02000000 -#define INT_STS_RXSTOP_INT_ 0x01000000 -#define INT_STS_RXDFH_INT_ 0x00800000 -#define INT_STS_RXDF_INT_ 0x00400000 -#define INT_STS_TX_IOC_ 0x00200000 -#define INT_STS_RXD_INT_ 0x00100000 -#define INT_STS_GPT_INT_ 0x00080000 -#define INT_STS_PHY_INT_ 0x00040000 -#define INT_STS_PME_INT_ 0x00020000 -#define INT_STS_TXSO_ 0x00010000 -#define INT_STS_RWT_ 0x00008000 -#define INT_STS_RXE_ 0x00004000 -#define INT_STS_TXE_ 0x00002000 -#define INT_STS_TDFU_ 0x00000800 -#define INT_STS_TDFO_ 0x00000400 -#define INT_STS_TDFA_ 0x00000200 -#define INT_STS_TSFF_ 0x00000100 -#define INT_STS_TSFL_ 0x00000080 -#define INT_STS_RXDF_ 0x00000040 -#define INT_STS_RDFL_ 0x00000020 -#define INT_STS_RSFF_ 0x00000010 -#define INT_STS_RSFL_ 0x00000008 -#define INT_STS_GPIO2_INT_ 0x00000004 -#define INT_STS_GPIO1_INT_ 0x00000002 -#define INT_STS_GPIO0_INT_ 0x00000001 - -#define INT_EN 0x5C -#define INT_EN_SW_INT_EN_ 0x80000000 -#define INT_EN_TXSTOP_INT_EN_ 0x02000000 -#define INT_EN_RXSTOP_INT_EN_ 0x01000000 -#define INT_EN_RXDFH_INT_EN_ 0x00800000 -#define INT_EN_TIOC_INT_EN_ 0x00200000 -#define INT_EN_RXD_INT_EN_ 0x00100000 -#define INT_EN_GPT_INT_EN_ 0x00080000 -#define INT_EN_PHY_INT_EN_ 0x00040000 -#define INT_EN_PME_INT_EN_ 0x00020000 -#define INT_EN_TXSO_EN_ 0x00010000 -#define INT_EN_RWT_EN_ 0x00008000 -#define INT_EN_RXE_EN_ 0x00004000 -#define INT_EN_TXE_EN_ 0x00002000 -#define INT_EN_TDFU_EN_ 0x00000800 -#define INT_EN_TDFO_EN_ 0x00000400 -#define INT_EN_TDFA_EN_ 0x00000200 -#define INT_EN_TSFF_EN_ 0x00000100 -#define INT_EN_TSFL_EN_ 0x00000080 -#define INT_EN_RXDF_EN_ 0x00000040 -#define INT_EN_RDFL_EN_ 0x00000020 -#define INT_EN_RSFF_EN_ 0x00000010 -#define INT_EN_RSFL_EN_ 0x00000008 -#define INT_EN_GPIO2_INT_ 0x00000004 -#define INT_EN_GPIO1_INT_ 0x00000002 -#define INT_EN_GPIO0_INT_ 0x00000001 - -#define BYTE_TEST 0x64 - -#define FIFO_INT 0x68 -#define FIFO_INT_TX_AVAIL_LEVEL_ 0xFF000000 -#define FIFO_INT_TX_STS_LEVEL_ 0x00FF0000 -#define FIFO_INT_RX_AVAIL_LEVEL_ 0x0000FF00 -#define FIFO_INT_RX_STS_LEVEL_ 0x000000FF - -#define RX_CFG 0x6C -#define RX_CFG_RX_END_ALGN_ 0xC0000000 -#define RX_CFG_RX_END_ALGN4_ 0x00000000 -#define RX_CFG_RX_END_ALGN16_ 0x40000000 -#define RX_CFG_RX_END_ALGN32_ 0x80000000 -#define RX_CFG_RX_DMA_CNT_ 0x0FFF0000 -#define RX_CFG_RX_DUMP_ 0x00008000 -#define RX_CFG_RXDOFF_ 0x00001F00 - -#define TX_CFG 0x70 -#define TX_CFG_TXS_DUMP_ 0x00008000 -#define TX_CFG_TXD_DUMP_ 0x00004000 -#define TX_CFG_TXSAO_ 0x00000004 -#define TX_CFG_TX_ON_ 0x00000002 -#define TX_CFG_STOP_TX_ 0x00000001 - -#define HW_CFG 0x74 -#define HW_CFG_TTM_ 0x00200000 -#define HW_CFG_SF_ 0x00100000 -#define HW_CFG_TX_FIF_SZ_ 0x000F0000 -#define HW_CFG_TR_ 0x00003000 -#define HW_CFG_SRST_ 0x00000001 - -/* only available on 115/117 */ -#define HW_CFG_PHY_CLK_SEL_ 0x00000060 -#define HW_CFG_PHY_CLK_SEL_INT_PHY_ 0x00000000 -#define HW_CFG_PHY_CLK_SEL_EXT_PHY_ 0x00000020 -#define HW_CFG_PHY_CLK_SEL_CLK_DIS_ 0x00000040 -#define HW_CFG_SMI_SEL_ 0x00000010 -#define HW_CFG_EXT_PHY_DET_ 0x00000008 -#define HW_CFG_EXT_PHY_EN_ 0x00000004 -#define HW_CFG_SRST_TO_ 0x00000002 - -/* only available on 116/118 */ -#define HW_CFG_32_16_BIT_MODE_ 0x00000004 - -#define RX_DP_CTRL 0x78 -#define RX_DP_CTRL_RX_FFWD_ 0x80000000 - -#define RX_FIFO_INF 0x7C -#define RX_FIFO_INF_RXSUSED_ 0x00FF0000 -#define RX_FIFO_INF_RXDUSED_ 0x0000FFFF - -#define TX_FIFO_INF 0x80 -#define TX_FIFO_INF_TSUSED_ 0x00FF0000 -#define TX_FIFO_INF_TDFREE_ 0x0000FFFF - -#define PMT_CTRL 0x84 -#define PMT_CTRL_PM_MODE_ 0x00003000 -#define PMT_CTRL_PM_MODE_D0_ 0x00000000 -#define PMT_CTRL_PM_MODE_D1_ 0x00001000 -#define PMT_CTRL_PM_MODE_D2_ 0x00002000 -#define PMT_CTRL_PM_MODE_D3_ 0x00003000 -#define PMT_CTRL_PHY_RST_ 0x00000400 -#define PMT_CTRL_WOL_EN_ 0x00000200 -#define PMT_CTRL_ED_EN_ 0x00000100 -#define PMT_CTRL_PME_TYPE_ 0x00000040 -#define PMT_CTRL_WUPS_ 0x00000030 -#define PMT_CTRL_WUPS_NOWAKE_ 0x00000000 -#define PMT_CTRL_WUPS_ED_ 0x00000010 -#define PMT_CTRL_WUPS_WOL_ 0x00000020 -#define PMT_CTRL_WUPS_MULTI_ 0x00000030 -#define PMT_CTRL_PME_IND_ 0x00000008 -#define PMT_CTRL_PME_POL_ 0x00000004 -#define PMT_CTRL_PME_EN_ 0x00000002 -#define PMT_CTRL_READY_ 0x00000001 - -#define GPIO_CFG 0x88 -#define GPIO_CFG_LED3_EN_ 0x40000000 -#define GPIO_CFG_LED2_EN_ 0x20000000 -#define GPIO_CFG_LED1_EN_ 0x10000000 -#define GPIO_CFG_GPIO2_INT_POL_ 0x04000000 -#define GPIO_CFG_GPIO1_INT_POL_ 0x02000000 -#define GPIO_CFG_GPIO0_INT_POL_ 0x01000000 -#define GPIO_CFG_EEPR_EN_ 0x00700000 -#define GPIO_CFG_GPIOBUF2_ 0x00040000 -#define GPIO_CFG_GPIOBUF1_ 0x00020000 -#define GPIO_CFG_GPIOBUF0_ 0x00010000 -#define GPIO_CFG_GPIODIR2_ 0x00000400 -#define GPIO_CFG_GPIODIR1_ 0x00000200 -#define GPIO_CFG_GPIODIR0_ 0x00000100 -#define GPIO_CFG_GPIOD4_ 0x00000020 -#define GPIO_CFG_GPIOD3_ 0x00000010 -#define GPIO_CFG_GPIOD2_ 0x00000004 -#define GPIO_CFG_GPIOD1_ 0x00000002 -#define GPIO_CFG_GPIOD0_ 0x00000001 - -#define GPT_CFG 0x8C -#define GPT_CFG_TIMER_EN_ 0x20000000 -#define GPT_CFG_GPT_LOAD_ 0x0000FFFF - -#define GPT_CNT 0x90 -#define GPT_CNT_GPT_CNT_ 0x0000FFFF - -#define ENDIAN 0x98 - -#define FREE_RUN 0x9C - -#define RX_DROP 0xA0 - -#define MAC_CSR_CMD 0xA4 -#define MAC_CSR_CMD_CSR_BUSY_ 0x80000000 -#define MAC_CSR_CMD_R_NOT_W_ 0x40000000 -#define MAC_CSR_CMD_CSR_ADDR_ 0x000000FF - -#define MAC_CSR_DATA 0xA8 - -#define AFC_CFG 0xAC -#define AFC_CFG_AFC_HI_ 0x00FF0000 -#define AFC_CFG_AFC_LO_ 0x0000FF00 -#define AFC_CFG_BACK_DUR_ 0x000000F0 -#define AFC_CFG_FCMULT_ 0x00000008 -#define AFC_CFG_FCBRD_ 0x00000004 -#define AFC_CFG_FCADD_ 0x00000002 -#define AFC_CFG_FCANY_ 0x00000001 - -#define E2P_CMD 0xB0 -#define E2P_CMD_EPC_BUSY_ 0x80000000 -#define E2P_CMD_EPC_CMD_ 0x70000000 -#define E2P_CMD_EPC_CMD_READ_ 0x00000000 -#define E2P_CMD_EPC_CMD_EWDS_ 0x10000000 -#define E2P_CMD_EPC_CMD_EWEN_ 0x20000000 -#define E2P_CMD_EPC_CMD_WRITE_ 0x30000000 -#define E2P_CMD_EPC_CMD_WRAL_ 0x40000000 -#define E2P_CMD_EPC_CMD_ERASE_ 0x50000000 -#define E2P_CMD_EPC_CMD_ERAL_ 0x60000000 -#define E2P_CMD_EPC_CMD_RELOAD_ 0x70000000 -#define E2P_CMD_EPC_TIMEOUT_ 0x00000200 -#define E2P_CMD_MAC_ADDR_LOADED_ 0x00000100 -#define E2P_CMD_EPC_ADDR_ 0x000000FF - -#define E2P_DATA 0xB4 -#define E2P_DATA_EEPROM_DATA_ 0x000000FF -#define LAN_REGISTER_EXTENT 0x00000100 - -/* - * MAC Control and Status Register (Indirect Address) - * Offset (through the MAC_CSR CMD and DATA port) - */ -#define MAC_CR 0x01 -#define MAC_CR_RXALL_ 0x80000000 -#define MAC_CR_HBDIS_ 0x10000000 -#define MAC_CR_RCVOWN_ 0x00800000 -#define MAC_CR_LOOPBK_ 0x00200000 -#define MAC_CR_FDPX_ 0x00100000 -#define MAC_CR_MCPAS_ 0x00080000 -#define MAC_CR_PRMS_ 0x00040000 -#define MAC_CR_INVFILT_ 0x00020000 -#define MAC_CR_PASSBAD_ 0x00010000 -#define MAC_CR_HFILT_ 0x00008000 -#define MAC_CR_HPFILT_ 0x00002000 -#define MAC_CR_LCOLL_ 0x00001000 -#define MAC_CR_BCAST_ 0x00000800 -#define MAC_CR_DISRTY_ 0x00000400 -#define MAC_CR_PADSTR_ 0x00000100 -#define MAC_CR_BOLMT_MASK_ 0x000000C0 -#define MAC_CR_DFCHK_ 0x00000020 -#define MAC_CR_TXEN_ 0x00000008 -#define MAC_CR_RXEN_ 0x00000004 - -#define ADDRH 0x02 - -#define ADDRL 0x03 - -#define HASHH 0x04 - -#define HASHL 0x05 - -#define MII_ACC 0x06 -#define MII_ACC_PHY_ADDR_ 0x0000F800 -#define MII_ACC_MIIRINDA_ 0x000007C0 -#define MII_ACC_MII_WRITE_ 0x00000002 -#define MII_ACC_MII_BUSY_ 0x00000001 - -#define MII_DATA 0x07 - -#define FLOW 0x08 -#define FLOW_FCPT_ 0xFFFF0000 -#define FLOW_FCPASS_ 0x00000004 -#define FLOW_FCEN_ 0x00000002 -#define FLOW_FCBSY_ 0x00000001 - -#define VLAN1 0x09 - -#define VLAN2 0x0A - -#define WUFF 0x0B - -#define WUCSR 0x0C -#define WUCSR_GUE_ 0x00000200 -#define WUCSR_WUFR_ 0x00000040 -#define WUCSR_MPR_ 0x00000020 -#define WUCSR_WAKE_EN_ 0x00000004 -#define WUCSR_MPEN_ 0x00000002 - -/* - * Phy definitions (vendor-specific) - */ -#define LAN9118_PHY_ID 0x00C0001C - -#define MII_INTSTS 0x1D - -#define MII_INTMSK 0x1E -#define PHY_INTMSK_AN_RCV_ (1 << 1) -#define PHY_INTMSK_PDFAULT_ (1 << 2) -#define PHY_INTMSK_AN_ACK_ (1 << 3) -#define PHY_INTMSK_LNKDOWN_ (1 << 4) -#define PHY_INTMSK_RFAULT_ (1 << 5) -#define PHY_INTMSK_AN_COMP_ (1 << 6) -#define PHY_INTMSK_ENERGYON_ (1 << 7) -#define PHY_INTMSK_DEFAULT_ (PHY_INTMSK_ENERGYON_ | \ - PHY_INTMSK_AN_COMP_ | \ - PHY_INTMSK_RFAULT_ | \ - PHY_INTMSK_LNKDOWN_) - -#define ADVERTISE_PAUSE_ALL (ADVERTISE_PAUSE_CAP | \ - ADVERTISE_PAUSE_ASYM) - -#define LPA_PAUSE_ALL (LPA_PAUSE_CAP | \ - LPA_PAUSE_ASYM) - -#endif /* __SMSC911X_H__ */ diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index d41e74acf785..057110147e88 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -290,6 +290,13 @@ config AT91_CF Say Y here to support the CompactFlash controller on AT91 chips. Or choose M to compile the driver as a module named "at91_cf". +config S3C2443_PCMCIA + tristate "S3C2443 PCMCIA driver" + depends on PCMCIA && CPU_S3C2443 + help + Say Y here to support the CompactFlash/PCMCIA interface with the + S3C2443 SoC + config PCMCIA_MX31ADS tristate "MX31ADS PCMCIA support" depends on ARM && MACH_MX31ADS && PCMCIA diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 2eebf736d600..cf0c7a7d123c 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o obj-$(CONFIG_OMAP_CF) += omap_cf.o obj-$(CONFIG_BFIN_CFPCMCIA) += bfin_cf_pcmcia.o obj-$(CONFIG_AT91_CF) += at91_cf.o +obj-$(CONFIG_S3C2443_PCMCIA) += s3c2443_pcmcia.o obj-$(CONFIG_ELECTRA_CF) += electra_cf.o obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD) += db1xxx_ss.o obj-$(CONFIG_PCMCIA_MX31ADS) += mx31ads-pcmcia.o diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c index a9d6c5626a0a..f1b27e6936c3 100644 --- a/drivers/serial/samsung.c +++ b/drivers/serial/samsung.c @@ -679,8 +679,10 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, baud = uart_get_baud_rate(port, termios, old, 0, 115200*8); - if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) + if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) { quot = port->custom_divisor; + clksrc = &tmp_clksrc; + } else quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud); @@ -795,11 +797,31 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, static const char *s3c24xx_serial_type(struct uart_port *port) { +#if defined(CONFIG_MACH_CC9M2443JS) + struct platform_device *pdev; + struct s3c2410_uartcfg *cfg; +#endif + switch (port->type) { case PORT_S3C2410: return "S3C2410"; case PORT_S3C2440: + #if defined(CONFIG_MACH_CC9M2443JS) + pdev = to_platform_device(port->dev); + cfg = s3c24xx_dev_to_cfg(&pdev->dev); + if (0 == cfg->hwport) + return "S3C2410 PORT A"; + else if (1 == cfg->hwport) + return "S3C2410 PORT B"; + else if (2 == cfg->hwport) + return "S3C2410 PORT C"; + else if (3 == cfg->hwport) + return "S3C2410 PORT D"; + else + return NULL; +#else return "S3C2440"; +#endif case PORT_S3C2412: return "S3C2412"; case PORT_S3C6400: @@ -878,10 +900,10 @@ static struct uart_ops s3c24xx_serial_ops = { static struct uart_driver s3c24xx_uart_drv = { .owner = THIS_MODULE, - .dev_name = "s3c2410_serial", + .driver_name = "s3c2410_serial", .nr = CONFIG_SERIAL_SAMSUNG_UARTS, .cons = S3C24XX_SERIAL_CONSOLE, - .driver_name = S3C24XX_SERIAL_NAME, + .dev_name = S3C24XX_SERIAL_NAME, .major = S3C24XX_SERIAL_MAJOR, .minor = S3C24XX_SERIAL_MINOR, }; @@ -1097,6 +1119,10 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, port->mapbase = res->start; port->membase = S3C_VA_UART + res->start - (S3C_PA_UART & 0xfff00000); + + /* Use the number of the HW port as line number (Luis Galdos) */ + port->line = cfg->hwport; + ret = platform_get_irq(platdev, 0); if (ret < 0) port->irq = 0; diff --git a/drivers/spi/spi_s3c2443.c b/drivers/spi/spi_s3c2443.c index 7b0d087776dc..336b986d7ad0 100644 --- a/drivers/spi/spi_s3c2443.c +++ b/drivers/spi/spi_s3c2443.c @@ -37,11 +37,12 @@ #include #include #include -#include +#include #include -#include +#include #include #include +#include /* This macro selects the virtual DMA-channel to use */ @@ -102,9 +103,9 @@ struct s3c2443_spi { dma_addr_t tx_dma; dma_addr_t rx_dma; - dmach_t dma_ch; + unsigned int dma_ch; struct s3c2410_dma_client dmach; - dmach_t dma_ch_rx; + unsigned int dma_ch_rx; struct s3c2410_dma_client dmach_rx; }; @@ -584,7 +585,7 @@ static void s3c2443_spi_dma_callback(struct s3c2410_dma_chan *ch, * amok! * Luis Galdos */ -static int s3c2443_spi_dma_init(dmach_t dma_ch, enum s3c2443_xfer_t mode, +static int s3c2443_spi_dma_init(unsigned int dma_ch, enum s3c2443_xfer_t mode, int length) { int xmode; @@ -598,7 +599,6 @@ static int s3c2443_spi_dma_init(dmach_t dma_ch, enum s3c2443_xfer_t mode, * system memory */ s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_MEM, - S3C2410_DISRCC_INC | S3C2410_DISRCC_APB, S3C2443_SPI0_TX_DATA_PA); } else if (mode == S3C2443_DMA_RX) { /* @@ -607,7 +607,6 @@ static int s3c2443_spi_dma_init(dmach_t dma_ch, enum s3c2443_xfer_t mode, * the address */ s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_HW, - S3C2410_DISRCC_INC | S3C2410_DISRCC_APB, S3C2443_SPI0_RX_DATA_PA); } else { printk_err("Invalid DMA transfer mode (%i)\n", mode); @@ -628,10 +627,7 @@ static int s3c2443_spi_dma_init(dmach_t dma_ch, enum s3c2443_xfer_t mode, /* @XXX: Don't use the burst mode, then it's not working with this driver */ s3c2410_dma_config(dma_ch, - xmode, - S3C2410_DCON_HANDSHAKE | - S3C2410_DCON_SYNC_PCLK | - S3C2410_DCON_HWTRIG); + xmode); s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_AUTOSTART); return 0; diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 5b6b913d66b6..b38438fd8c75 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -316,6 +316,21 @@ config USB_IMX default USB_GADGET select USB_GADGET_SELECTED +config USB_GADGET_S3C2443 + boolean "S3C2443 USB Device Controller" + depends on S3C2443_USB_PHY_UDC + select USB_GADGET_SELECTED + help + Samsung's S3C2443 with an integrated full speed USB 2.0 device + controller. + +config USB_S3C2443 + tristate + depends on USB_GADGET_S3C2443 + default USB_GADGET + select USB_GADGET_SELECTED + select USB_GADGET_DUALSPEED + config USB_GADGET_S3C2410 boolean "S3C2410 USB Device Controller" depends on ARCH_S3C2410 diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index 9820bf0955f1..e24979a096a6 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -120,6 +120,13 @@ #define gadget_is_fsl_qe(g) 0 #endif +/* Samsung S3C2443 UDC */ +#ifdef CONFIG_USB_GADGET_S3C2443 +#define gadget_is_s3c2443(g) !strcmp("s3c2443_udc", (g)->name) +#else +#define gadget_is_s3c2443(g) 0 +#endif + #ifdef CONFIG_USB_GADGET_CI13XXX #define gadget_is_ci13xxx(g) (!strcmp("ci13xxx_udc", (g)->name)) #else @@ -207,7 +214,9 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) else if (gadget_is_s3c_hsotg(gadget)) return 0x26; else if (gadget_is_arcotg(gadget)) - return 0x26; + return 0x27; + else if (gadget_is_s3c2443(gadget)) + return 0x28; return -ENOENT; } diff --git a/drivers/usb/gadget/s3c2443_udc.c b/drivers/usb/gadget/s3c2443_udc.c index 3eaf7d14f84a..8c3d28479399 100644 --- a/drivers/usb/gadget/s3c2443_udc.c +++ b/drivers/usb/gadget/s3c2443_udc.c @@ -371,10 +371,10 @@ static inline int s3c2443_udc_vbus_state(struct s3c24xx_udc *udc) unsigned long iocfg; /* @XXX: Do we really need to change to INPUT first? */ - iocfg = s3c2410_gpio_getcfg(info->vbus_pin); - s3c2410_gpio_cfgpin(info->vbus_pin, S3C2410_GPIO_INPUT); + iocfg = s3c_gpio_getcfg(info->vbus_pin); + s3c_gpio_cfgpin(info->vbus_pin, S3C2410_GPIO_INPUT); retval = s3c2410_gpio_getpin(info->vbus_pin); - s3c2410_gpio_cfgpin(info->vbus_pin, iocfg); + s3c_gpio_cfgpin(info->vbus_pin, iocfg); if (info->vbus_pin_inverted) retval = !retval; @@ -660,7 +660,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) info = udc->mach_info; - iocfg = s3c2410_gpio_getcfg(info->vbus_pin); + iocfg = s3c_gpio_getcfg(info->vbus_pin); s3c2410_gpio_cfgpin(info->vbus_pin, S3C2410_GPIO_INPUT); state = s3c2410_gpio_getpin(info->vbus_pin); s3c2410_gpio_cfgpin(info->vbus_pin, iocfg); @@ -1330,7 +1330,7 @@ static irqreturn_t s3c24xx_udc_vbus_irq(int irq, void *_udc) info = udc->mach_info; /* Some cpus cannot read from an line configured to IRQ! */ - cfg = s3c2410_gpio_getcfg(info->vbus_pin); + cfg = s3c_gpio_getcfg(info->vbus_pin); s3c2410_gpio_cfgpin(info->vbus_pin, S3C2410_GPIO_INPUT); value = s3c2410_gpio_getpin(info->vbus_pin); s3c2410_gpio_cfgpin(info->vbus_pin, cfg); @@ -2369,7 +2369,7 @@ static const struct usb_gadget_ops s3c_udc_ops = { static void nop_release(struct device *dev) { - pk_dbg("%s %s\n", __FUNCTION__, dev->bus_id); + pk_dbg("%s %s\n", __FUNCTION__, dev->init_name); } /* @@ -2386,7 +2386,7 @@ static struct s3c24xx_udc memory = { .ep0 = &memory.ep[0].ep, .name = DRIVER_NAME, .dev = { - .bus_id = "gadget", + .init_name = "gadget", .release = nop_release, }, }, @@ -2587,7 +2587,7 @@ static int s3c24xx_udc_probe(struct platform_device *pdev) pk_dbg("IRQ %i for the UDC\n", IRQ_USBD); if (mach_info && mach_info->vbus_pin > 0) { - udc->irq_vbus = s3c2410_gpio_getirq(mach_info->vbus_pin); + udc->irq_vbus = gpio_to_irq(mach_info->vbus_pin); retval = request_irq(udc->irq_vbus, s3c24xx_udc_vbus_irq, IRQF_DISABLED | IRQF_SHARED | diff --git a/drivers/usb/gadget/s3c2443_udc.h b/drivers/usb/gadget/s3c2443_udc.h index f22985128cff..2c1c13549ada 100644 --- a/drivers/usb/gadget/s3c2443_udc.h +++ b/drivers/usb/gadget/s3c2443_udc.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -48,14 +49,15 @@ #include #include #include -#include +#include +#include #include #include -#include -#include +#include +#include #include #include #include diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 64349561386a..dbca327a29ee 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -304,7 +304,7 @@ static long s3c2410wdt_ioctl(struct file *file, unsigned int cmd, return -EFAULT; if (value & WDIOS_DISABLECARD) { if (!nowayout) { - allow_close = CLOSE_STATE_ALLOW; + expect_close = 42; } else { printk("WATCHDOG_NOWAYOUT enabled in kernel. Cannot disable!\n"); -- cgit v1.2.3