diff options
Diffstat (limited to 'target/linux/adm8668/files')
22 files changed, 881 insertions, 2705 deletions
diff --git a/target/linux/adm8668/files/arch/mips/adm8668/Kconfig b/target/linux/adm8668/files/arch/mips/adm8668/Kconfig new file mode 100644 index 000000000..2e7281ff0 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/Kconfig @@ -0,0 +1,2 @@ +config ARM_AMBA + def_bool y diff --git a/target/linux/adm8668/files/arch/mips/adm8668/Makefile b/target/linux/adm8668/files/arch/mips/adm8668/Makefile index 0b31b97d4..515c3a499 100644 --- a/target/linux/adm8668/files/arch/mips/adm8668/Makefile +++ b/target/linux/adm8668/files/arch/mips/adm8668/Makefile @@ -2,4 +2,5 @@ # something witty --neutronscott # -obj-y := irq.o pci.o prom.o platform.o serial.o proc.o net_core.o net_intr.o +obj-y := irq.o prom.o platform.o gpio.o \ + setup.o clock.o time.o early_printk.o \ diff --git a/target/linux/adm8668/files/arch/mips/adm8668/clock.c b/target/linux/adm8668/files/arch/mips/adm8668/clock.c new file mode 100644 index 000000000..1e010fcc8 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/clock.c @@ -0,0 +1,76 @@ +/* + * ADM8668 minimal clock support + * + * Copyright (C) 2012, Florian Fainelli <florian@openwrt.org> + * + * Licensed under the terms of the GPLv2 + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/clk.h> + +#include <adm8668.h> + +struct clk { + unsigned long rate; +}; + +static struct clk uart_clk = { + .rate = 62500000, +}; + +static struct clk sys_clk; + +struct clk *clk_get(struct device *dev, const char *id) +{ + const char *lookup = id; + + if (dev) + lookup = dev_name(dev); + + if (!strcmp(lookup, "apb:uart0")) + return &uart_clk; + if (!strcmp(lookup, "sys")) + return &sys_clk; + + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL(clk_get); + +int clk_enable(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL(clk_enable); + +void clk_disable(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + return clk->rate; +} +EXPORT_SYMBOL(clk_get_rate); + +void clk_put(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_put); + +void __init adm8668_init_clocks(void) +{ + u32 adj; + + /* adjustable clock selection + * CR3 bit 14~11, 0000 -> 175MHz, 0001 -> 180MHz, etc... + */ + adj = (ADM8668_CONFIG_REG(ADM8668_CR3) >> 11) & 0xf; + sys_clk.rate = 175000000 + (adj * 5000000); + + pr_info("ADM8668 CPU clock: %lu MHz\n", sys_clk.rate / 1000000); +} diff --git a/target/linux/adm8668/files/arch/mips/adm8668/early_printk.c b/target/linux/adm8668/files/arch/mips/adm8668/early_printk.c new file mode 100644 index 000000000..03dd72aa8 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/early_printk.c @@ -0,0 +1,16 @@ +#include <linux/io.h> +#include <linux/amba/serial.h> +#include <adm8668.h> + +#define UART_READ(r) \ + __raw_readl((void __iomem *)(KSEG1ADDR(ADM8668_UART0_BASE) + (r))) + +#define UART_WRITE(v, r) \ + __raw_writel((v), (void __iomem *)(KSEG1ADDR(ADM8668_UART0_BASE) + (r))) + +void prom_putchar(char c) +{ + UART_WRITE(c, UART01x_DR); + while ((UART_READ(UART01x_FR) & UART01x_FR_TXFF) != 0) + ; +} diff --git a/target/linux/adm8668/files/arch/mips/adm8668/gpio.c b/target/linux/adm8668/files/arch/mips/adm8668/gpio.c new file mode 100644 index 000000000..fb39f7f58 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/gpio.c @@ -0,0 +1,123 @@ +/* + * Infineon/ADMTek ADM8668 WildPass GPIO support + * + * Copyright (C) 2012 Florian Fainelli <florian@openwrt.org> + * + * Licensed under the terms of GPLv2. + * + */ +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/io.h> + +#include <adm8668.h> + +#define GPIO_MASK 0x3f + +#define GPIO_IN_OFS 0 +#define GPIO_OUT_OFS 6 +#define GPIO_OE_OFS 12 + +struct adm8668_gpio_chip { + void __iomem *base; + struct gpio_chip chip; +}; + +static int adm8668_gpio_dir_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct adm8668_gpio_chip *c = + container_of(chip, struct adm8668_gpio_chip, chip); + u32 mask; + + /* clear input, set output enable and output value */ + mask = __raw_readl(c->base); + mask &= ~(1 << offset); + mask |= (1 << (offset + GPIO_OE_OFS)); + if (value) + mask |= (1 << (offset + GPIO_OUT_OFS)); + else + mask &= ~(1 << (offset + GPIO_OUT_OFS)); + __raw_writel(mask, c->base); + + return 0; +} + +static int adm8668_gpio_dir_in(struct gpio_chip *chip, + unsigned offset) +{ + struct adm8668_gpio_chip *c = + container_of(chip, struct adm8668_gpio_chip, chip); + u32 mask; + + mask = __raw_readl(c->base); + mask &= ~(((1 << (offset + GPIO_OE_OFS)) | (1 << (offset + GPIO_OUT_OFS)))); + mask |= (1 << offset); + __raw_writel(mask, c->base); + + return 0; +} + +static void adm8668_gpio_set(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct adm8668_gpio_chip *c = + container_of(chip, struct adm8668_gpio_chip, chip); + u32 mask; + + mask = __raw_readl(c->base); + if (value) + mask |= (1 << (offset + GPIO_OUT_OFS)); + else + mask &= ~(1 << (offset + GPIO_OUT_OFS)); + __raw_writel(mask, c->base); +} + +static int adm8668_gpio_get(struct gpio_chip *chip, + unsigned offset) +{ + struct adm8668_gpio_chip *c = + container_of(chip, struct adm8668_gpio_chip, chip); + u32 value; + + value = __raw_readl(c->base) & GPIO_MASK; + + return value & (1 << offset); +} + +static struct adm8668_gpio_chip adm8668_gpio_cpu = { + .base = (void __iomem *)KSEG1ADDR(ADM8668_CONFIG_BASE + CRGPIO_REG), + .chip = { + .label = "adm8668-cpu-gpio", + .direction_output = adm8668_gpio_dir_out, + .direction_input = adm8668_gpio_dir_in, + .set = adm8668_gpio_set, + .get = adm8668_gpio_get, + .ngpio = 6, + }, +}; + +static struct adm8668_gpio_chip adm8668_gpio_wlan = { + .base = (void __iomem *)KSEG1ADDR(ADM8668_WLAN_BASE + GPIO_REG), + .chip = { + .label = "adm8668-wlan-gpio", + .direction_output = adm8668_gpio_dir_out, + .direction_input = adm8668_gpio_dir_in, + .set = adm8668_gpio_set, + .get = adm8668_gpio_get, + .ngpio = 6, + .base = 6, + }, +}; + +static int __init adm8668_gpio_init(void) +{ + int ret; + + ret = gpiochip_add(&adm8668_gpio_cpu.chip); + if (ret) + return ret; + + return gpiochip_add(&adm8668_gpio_wlan.chip); +} +arch_initcall(adm8668_gpio_init); diff --git a/target/linux/adm8668/files/arch/mips/adm8668/irq.c b/target/linux/adm8668/files/arch/mips/adm8668/irq.c index e048c15c8..9d3b2b9b8 100644 --- a/target/linux/adm8668/files/arch/mips/adm8668/irq.c +++ b/target/linux/adm8668/files/arch/mips/adm8668/irq.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> + * Copyright (C) 2012 Florian Fainelli <florian@openwrt.org> * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -20,15 +21,38 @@ #include <asm/irq.h> #include <adm8668.h> -static void adm8668_irq_cascade(void) +/* interrupt controller */ +#define IRQ_STATUS_REG 0x00 /* Read */ +#define IRQ_ENABLE_REG 0x08 /* Read/Write */ +#define IRQ_DISABLE_REG 0x0C /* Write */ + +#define IRQ_MASK 0xffff + +static inline void intc_write_reg(u32 val, unsigned int reg) { - int i; - unsigned long intsrc; + void __iomem *base = (void __iomem *)KSEG1ADDR(ADM8668_INTC_BASE); + + __raw_writel(val, base + reg); +} - intsrc = ADM8668_INTC_REG(IRQ_STATUS_REG) & IRQ_MASK; - for (i = 0; intsrc; intsrc >>= 1, i++) - if (intsrc & 0x1) - do_IRQ(i); +static inline u32 intc_read_reg(unsigned int reg) +{ + void __iomem *base = (void __iomem *)KSEG1ADDR(ADM8668_INTC_BASE); + + return __raw_readl(base + reg); +} + +static void adm8668_irq_cascade(void) +{ + int irq; + u32 intsrc; + + intsrc = intc_read_reg(IRQ_STATUS_REG) & IRQ_MASK; + if (intsrc) { + irq = fls(intsrc) - 1; + do_IRQ(irq); + } else + spurious_interrupt(); } /* @@ -43,8 +67,10 @@ void plat_irq_dispatch(void) /* timer interrupt, that we renumbered */ if (pending & STATUSF_IP7) do_IRQ(MIPS_CPU_IRQ_BASE + 7); - if (pending & STATUSF_IP2) + else if (pending & STATUSF_IP2) adm8668_irq_cascade(); + else + spurious_interrupt(); } /* @@ -52,33 +78,13 @@ void plat_irq_dispatch(void) */ static void enable_adm8668_irq(struct irq_data *d) { - int irq = d->irq; - - if ((irq < 0) || (irq > NR_IRQS)) - return; - - ADM8668_INTC_REG(IRQ_ENABLE_REG) = (1 << irq); + intc_write_reg((1 << d->irq), IRQ_ENABLE_REG); } -/* - * disable 8668 irq - */ -static void disable_adm8668_irq(struct irq_data *d) -{ - int irq = d->irq; - - if ((irq < 0) || (irq > NR_IRQS)) - return; - - ADM8668_INTC_REG(IRQ_DISABLE_REG) = (1 << irq); -} - static void ack_adm8668_irq(struct irq_data *d) { - int irq = d->irq; - - ADM8668_INTC_REG(IRQ_DISABLE_REG) = (1 << irq); + intc_write_reg((1 << d->irq), IRQ_DISABLE_REG); } /* @@ -88,7 +94,7 @@ static void ack_adm8668_irq(struct irq_data *d) static struct irq_chip adm8668_irq_type = { .name = "adm8668", .irq_ack = ack_adm8668_irq, - .irq_mask = disable_adm8668_irq, + .irq_mask = ack_adm8668_irq, .irq_unmask = enable_adm8668_irq }; @@ -99,7 +105,10 @@ static void __init init_adm8668_irqs(void) { int i; - for (i = 0; i <= INT_LVL_MAX; i++) + /* disable all interrupts for the moment */ + intc_write_reg(IRQ_MASK, IRQ_DISABLE_REG); + + for (i = 0; i <= ADM8668_IRQ_MAX; i++) irq_set_chip_and_handler(i, &adm8668_irq_type, handle_level_irq); diff --git a/target/linux/adm8668/files/arch/mips/adm8668/net.h b/target/linux/adm8668/files/arch/mips/adm8668/net.h deleted file mode 100644 index c7aef8cf6..000000000 --- a/target/linux/adm8668/files/arch/mips/adm8668/net.h +++ /dev/null @@ -1,277 +0,0 @@ -/* - * originally drivers/net/tulip/tulip.h - * Copyright 2000,2001 The Linux Kernel Team - * Written/copyright 1994-2001 by Donald Becker. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#ifndef __NET_TULIP_H__ -#define __NET_TULIP_H__ - -#include <linux/module.h> -#include <linux/export.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/mii.h> -#include <linux/crc32.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/spinlock.h> -#include <linux/netdevice.h> -#include <linux/ethtool.h> -#include <linux/timer.h> -#include <linux/delay.h> -#include <linux/etherdevice.h> -#include <linux/platform_device.h> -#include <linux/io.h> -#include <linux/interrupt.h> -#include <asm/unaligned.h> -#include <asm/uaccess.h> - -/* undefine, or define to various debugging levels (>4 == obscene levels) */ -#define TULIP_DEBUG 1 -#define VALID_INTR 0x0001a451 -#define ADM8668_WAN_IRQ 8 -#define ADM8668_LAN_IRQ 7 -#define ADM8668_WAN_MACADDR 0xb00205ac -#define ADM8668_LAN_MACADDR 0xb0020404 - -/* Offsets to the Command and Status Registers, "CSRs". All accesses - must be longword instructions and quadword aligned. */ -enum tulip_offsets { - CSR0 = 0, - CSR1 = 0x08, - CSR2 = 0x10, - CSR3 = 0x18, - CSR4 = 0x20, - CSR5 = 0x28, - CSR6 = 0x30, - CSR7 = 0x38, - CSR8 = 0x40, - CSR9 = 0x48, - CSR10 = 0x50, - CSR11 = 0x58, - CSR12 = 0x60, - CSR13 = 0x68, - CSR14 = 0x70, - CSR15 = 0x78, - CSR18 = 0x88, - CSR19 = 0x8c, - CSR20 = 0x90, - CSR27 = 0xAC, - CSR28 = 0xB0, -}; - -#define RxPollInt (RxIntr|RxNoBuf|RxDied|RxJabber) - -/* The bits in the CSR5 status registers, mostly interrupt sources. */ -enum status_bits { - TimerInt = 0x800, - SystemError = 0x2000, - TPLnkFail = 0x1000, - TPLnkPass = 0x10, - NormalIntr = 0x10000, - AbnormalIntr = 0x8000, - RxJabber = 0x200, - RxDied = 0x100, - RxNoBuf = 0x80, - RxIntr = 0x40, - TxFIFOUnderflow = 0x20, - RxErrIntr = 0x10, - TxJabber = 0x08, - TxNoBuf = 0x04, - TxDied = 0x02, - TxIntr = 0x01, -}; - -/* bit mask for CSR5 TX/RX process state */ -#define CSR5_TS 0x00700000 -#define CSR5_RS 0x000e0000 - -enum tulip_mode_bits { - TxThreshold = (1 << 22), - FullDuplex = (1 << 9), - TxOn = 0x2000, - AcceptBroadcast = 0x0100, - AcceptAllMulticast = 0x0080, - AcceptAllPhys = 0x0040, - AcceptRunt = 0x0008, - RxOn = 0x0002, - RxTx = (TxOn | RxOn), -}; - -/* The Tulip Rx and Tx buffer descriptors. */ -struct tulip_rx_desc { - __le32 status; - __le32 length; - __le32 buffer1; - __le32 buffer2; -}; - -struct tulip_tx_desc { - __le32 status; - __le32 length; - __le32 buffer1; - __le32 buffer2; /* We use only buffer 1. */ -}; - -enum desc_status_bits { - DescOwned = 0x80000000, - DescWholePkt = 0x60000000, - DescEndPkt = 0x40000000, - DescStartPkt = 0x20000000, - DescEndRing = 0x02000000, - DescUseLink = 0x01000000, - - /* - * Error summary flag is logical or of 'CRC Error', 'Collision Seen', - * 'Frame Too Long', 'Runt' and 'Descriptor Error' flags generated - * within tulip chip. - */ - RxDescErrorSummary = 0x8000, - RxDescCRCError = 0x0002, - RxDescCollisionSeen = 0x0040, - - /* - * 'Frame Too Long' flag is set if packet length including CRC exceeds - * 1518. However, a full sized VLAN tagged frame is 1522 bytes - * including CRC. - * - * The tulip chip does not block oversized frames, and if this flag is - * set on a receive descriptor it does not indicate the frame has been - * truncated. The receive descriptor also includes the actual length. - * Therefore we can safety ignore this flag and check the length - * ourselves. - */ - RxDescFrameTooLong = 0x0080, - RxDescRunt = 0x0800, - RxDescDescErr = 0x4000, - RxWholePkt = 0x00000300, - /* - * Top three bits of 14 bit frame length (status bits 27-29) should - * never be set as that would make frame over 2047 bytes. The Receive - * Watchdog flag (bit 4) may indicate the length is over 2048 and the - * length field is invalid. - */ - RxLengthOver2047 = 0x38000010 -}; - -/* Keep the ring sizes a power of two for efficiency. - Making the Tx ring too large decreases the effectiveness of channel - bonding and packet priority. - There are no ill effects from too-large receive rings. */ - -#define TX_RING_SIZE 32 -#define RX_RING_SIZE 128 - -/* The receiver on the DC21143 rev 65 can fail to close the last - * receive descriptor in certain circumstances (see errata) when - * using MWI. This can only occur if the receive buffer ends on - * a cache line boundary, so the "+ 4" below ensures it doesn't. - */ -#define PKT_BUF_SZ (1536 + 4) /* Size of each temporary Rx buffer. */ - -/* Ring-wrap flag in length field, use for last ring entry. - 0x01000000 means chain on buffer2 address, - 0x02000000 means use the ring start address in CSR2/3. - Note: Some work-alike chips do not function correctly in chained mode. - The ASIX chip works only in chained mode. - Thus we indicates ring mode, but always write the 'next' field for - chained mode as well. -*/ -#define DESC_RING_WRAP 0x02000000 - -struct ring_info { - struct sk_buff *skb; - dma_addr_t mapping; -}; - -struct tulip_private { - struct tulip_rx_desc *rx_ring; - struct tulip_tx_desc *tx_ring; - dma_addr_t rx_ring_dma; - dma_addr_t tx_ring_dma; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct ring_info tx_buffers[TX_RING_SIZE]; - /* The addresses of receive-in-place skbuffs. */ - struct ring_info rx_buffers[RX_RING_SIZE]; - struct napi_struct napi; - struct net_device_stats stats; - struct timer_list oom_timer; /* Out of memory timer. */ - u32 mc_filter[2]; - spinlock_t lock; - unsigned int cur_rx, cur_tx; /* The next free ring entry */ - unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - unsigned int csr0; /* CSR0 setting. */ - unsigned int csr6; /* Current CSR6 control settings. */ - void (*link_change) (struct net_device * dev, int csr5); - struct platform_device *pdev; - unsigned long nir; - void __iomem *base_addr; - int pad0; /* Used for 8-byte alignment */ - struct net_device *dev; -}; - - -/* interrupt.c */ -irqreturn_t tulip_interrupt(int irq, void *dev_instance); -int tulip_refill_rx(struct net_device *dev); -int tulip_poll(struct napi_struct *napi, int budget); - -/* tulip_core.c */ -extern int tulip_debug; -void oom_timer(unsigned long data); - -static inline void tulip_start_rxtx(struct tulip_private *tp) -{ - void __iomem *ioaddr = tp->base_addr; - iowrite32(tp->csr6 | RxTx, ioaddr + CSR6); - barrier(); - (void) ioread32(ioaddr + CSR6); /* mmio sync */ -} - -static inline void tulip_stop_rxtx(struct tulip_private *tp) -{ - void __iomem *ioaddr = tp->base_addr; - u32 csr6 = ioread32(ioaddr + CSR6); - - if (csr6 & RxTx) { - unsigned i=1300/10; - iowrite32(csr6 & ~RxTx, ioaddr + CSR6); - barrier(); - /* wait until in-flight frame completes. - * Max time @ 10BT: 1500*8b/10Mbps == 1200us (+ 100us margin) - * Typically expect this loop to end in < 50 us on 100BT. - */ - while (--i && (ioread32(ioaddr + CSR5) & (CSR5_TS|CSR5_RS))) - udelay(10); - - if (!i) - printk(KERN_DEBUG "fixme: tulip_stop_rxtx() failed" - " (CSR5 0x%x CSR6 0x%x)\n", - ioread32(ioaddr + CSR5), - ioread32(ioaddr + CSR6)); - } -} - -static inline void tulip_restart_rxtx(struct tulip_private *tp) -{ - tulip_stop_rxtx(tp); - udelay(5); - tulip_start_rxtx(tp); -} - -static inline void tulip_tx_timeout_complete(struct tulip_private *tp, void __iomem *ioaddr) -{ - /* Stop and restart the chip's Tx processes. */ - tulip_restart_rxtx(tp); - /* Trigger an immediate transmit demand. */ - iowrite32(0, ioaddr + CSR1); - - tp->stats.tx_errors++; -} - -#endif /* __NET_TULIP_H__ */ diff --git a/target/linux/adm8668/files/arch/mips/adm8668/net_core.c b/target/linux/adm8668/files/arch/mips/adm8668/net_core.c deleted file mode 100644 index 3348c224b..000000000 --- a/target/linux/adm8668/files/arch/mips/adm8668/net_core.c +++ /dev/null @@ -1,618 +0,0 @@ -/* - * originally drivers/net/tulip_core.c - * Copyright 2000,2001 The Linux Kernel Team - * Written/copyright 1994-2001 by Donald Becker. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#define DRV_NAME "tulip" -#define DRV_VERSION "1.1.15-NAPI" /* Keep at least for test */ -#define DRV_RELDATE "Feb 27, 2007" - -#include "net.h" - -static char version[] __devinitdata = - "ADM8668net driver version " DRV_VERSION " (" DRV_RELDATE ")\n"; - -#define MAX_UNITS 2 - -/* - Set the bus performance register. - Typical: Set 16 longword cache alignment, no burst limit. - Cache alignment bits 15:14 Burst length 13:8 - 0000 No alignment 0x00000000 unlimited 0800 8 longwords - 4000 8 longwords 0100 1 longword 1000 16 longwords - 8000 16 longwords 0200 2 longwords 2000 32 longwords - C000 32 longwords 0400 4 longwords - Warning: many older 486 systems are broken and require setting 0x00A04800 - 8 longword cache alignment, 8 longword burst. - ToDo: Non-Intel setting could be better. -*/ - -//static int csr0 = 0x00200000 | 0x4000; -static int csr0 = 0; - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (4*HZ) - -MODULE_AUTHOR("Scott Nicholas <neutronscott@scottn.us>"); -MODULE_DESCRIPTION("ADM8668 new ethernet driver."); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); - -#ifdef TULIP_DEBUG -int tulip_debug = TULIP_DEBUG; -#else -int tulip_debug = 1; -#endif - -static void tulip_tx_timeout(struct net_device *dev); -static void tulip_init_ring(struct net_device *dev); -static void tulip_free_ring(struct net_device *dev); -static netdev_tx_t tulip_start_xmit(struct sk_buff *skb, - struct net_device *dev); -static int tulip_open(struct net_device *dev); -static int tulip_close(struct net_device *dev); -static void tulip_up(struct net_device *dev); -static void tulip_down(struct net_device *dev); -static struct net_device_stats *tulip_get_stats(struct net_device *dev); -//static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void set_rx_mode(struct net_device *dev); -#ifdef CONFIG_NET_POLL_CONTROLLER -static void poll_tulip(struct net_device *dev); -#endif - -static void tulip_up(struct net_device *dev) -{ - struct tulip_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->base_addr; - - napi_enable(&tp->napi); - - /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ - iowrite32(0x00000001, ioaddr + CSR0); - - /* Deassert reset. - Wait the specified 50 PCI cycles after a reset by initializing - Tx and Rx queues and the address filter list. */ - iowrite32(tp->csr0, ioaddr + CSR0); - - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: tulip_up(), irq==%d\n", - dev->name, dev->irq); - - iowrite32(tp->rx_ring_dma, ioaddr + CSR3); - iowrite32(tp->tx_ring_dma, ioaddr + CSR4); - tp->cur_rx = tp->cur_tx = 0; - tp->dirty_rx = tp->dirty_tx = 0; - - /* set mac address */ - iowrite32(get_unaligned_le32(dev->dev_addr), ioaddr + 0xA4); - iowrite32(get_unaligned_le16(dev->dev_addr + 4), ioaddr + 0xA8); - iowrite32(0, ioaddr + CSR27); - iowrite32(0, ioaddr + CSR28); - - tp->csr6 = 0; - - /* Enable automatic Tx underrun recovery. */ - iowrite32(ioread32(ioaddr + CSR18) | 1, ioaddr + CSR18); - tp->csr6 = 0x00040000; - - /* Start the chip's Tx to process setup frame. */ - tulip_stop_rxtx(tp); - barrier(); - udelay(5); - iowrite32(tp->csr6 | TxOn, ioaddr + CSR6); - - /* Enable interrupts by setting the interrupt mask. */ - iowrite32(VALID_INTR, ioaddr + CSR5); - iowrite32(VALID_INTR, ioaddr + CSR7); - tulip_start_rxtx(tp); - iowrite32(0, ioaddr + CSR2); /* Rx poll demand */ - - if (tulip_debug > 2) { - printk(KERN_DEBUG "%s: Done tulip_up(), CSR0 %08x, CSR5 %08x CSR6 %08x\n", - dev->name, ioread32(ioaddr + CSR0), - ioread32(ioaddr + CSR5), - ioread32(ioaddr + CSR6)); - } - - init_timer(&tp->oom_timer); - tp->oom_timer.data = (unsigned long)dev; - tp->oom_timer.function = oom_timer; -} - -static int -tulip_open(struct net_device *dev) -{ - int retval; - - tulip_init_ring (dev); - - retval = request_irq(dev->irq, tulip_interrupt, 0, dev->name, dev); - if (retval) - goto free_ring; - - tulip_up (dev); - - netif_start_queue (dev); - - return 0; - -free_ring: - tulip_free_ring (dev); - return retval; -} - - -static void tulip_tx_timeout(struct net_device *dev) -{ - struct tulip_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->base_addr; - unsigned long flags; - - spin_lock_irqsave (&tp->lock, flags); - - dev_warn(&dev->dev, - "Transmit timed out, status %08x, CSR12 %08x, resetting...\n", - ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12)); - - tulip_tx_timeout_complete(tp, ioaddr); - - spin_unlock_irqrestore (&tp->lock, flags); - dev->trans_start = jiffies; /* prevent tx timeout */ - netif_wake_queue (dev); -} - - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void tulip_init_ring(struct net_device *dev) -{ - struct tulip_private *tp = netdev_priv(dev); - int i; - - tp->nir = 0; - - for (i = 0; i < RX_RING_SIZE; i++) { - tp->rx_ring[i].status = 0x00000000; - tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ); - tp->rx_ring[i].buffer2 = cpu_to_le32(tp->rx_ring_dma + sizeof(struct tulip_rx_desc) * (i + 1)); - tp->rx_buffers[i].skb = NULL; - tp->rx_buffers[i].mapping = 0; - } - /* Mark the last entry as wrapping the ring. */ - tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP); - tp->rx_ring[i-1].buffer2 = cpu_to_le32(tp->rx_ring_dma); - - for (i = 0; i < RX_RING_SIZE; i++) { - dma_addr_t mapping; - /* Note the receive buffer must be longword aligned. - dev_alloc_skb() provides 16 byte alignment. But do *not* - use skb_reserve() to align the IP header! */ - struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ); - tp->rx_buffers[i].skb = skb; - if (skb == NULL) - break; - mapping = dma_map_single(&dev->dev, skb->data, - PKT_BUF_SZ, DMA_FROM_DEVICE); - tp->rx_buffers[i].mapping = mapping; - skb->dev = dev; /* Mark as being used by this device. */ - tp->rx_ring[i].status = cpu_to_le32(DescOwned); /* Owned by Tulip chip */ - tp->rx_ring[i].buffer1 = cpu_to_le32(mapping); - } - tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); - - /* The Tx buffer descriptor is filled in as needed, but we - do need to clear the ownership bit. */ - for (i = 0; i < TX_RING_SIZE; i++) { - tp->tx_buffers[i].skb = NULL; - tp->tx_buffers[i].mapping = 0; - tp->tx_ring[i].status = 0x00000000; - tp->tx_ring[i].buffer2 = cpu_to_le32(tp->tx_ring_dma + sizeof(struct tulip_tx_desc) * (i + 1)); - } - tp->tx_ring[i-1].buffer2 = cpu_to_le32(tp->tx_ring_dma); -} - -static netdev_tx_t -tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct tulip_private *tp = netdev_priv(dev); - int entry; - u32 flag; - dma_addr_t mapping; - unsigned long flags; - - spin_lock_irqsave(&tp->lock, flags); - - /* Calculate the next Tx descriptor entry. */ - entry = tp->cur_tx % TX_RING_SIZE; - - tp->tx_buffers[entry].skb = skb; - mapping = dma_map_single(&tp->pdev->dev, skb->data, skb->len, - DMA_TO_DEVICE); - tp->tx_buffers[entry].mapping = mapping; - tp->tx_ring[entry].buffer1 = cpu_to_le32(mapping); - - if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */ - flag = 0x60000000; /* No interrupt */ - } else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) { - flag = 0xe0000000; /* Tx-done intr. */ - } else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) { - flag = 0x60000000; /* No Tx-done intr. */ - } else { /* Leave room for set_rx_mode() to fill entries. */ - flag = 0xe0000000; /* Tx-done intr. */ - netif_stop_queue(dev); - } - if (entry == TX_RING_SIZE-1) - flag = 0xe0000000 | DESC_RING_WRAP; - - tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag); - /* if we were using Transmit Automatic Polling, we would need a - * wmb() here. */ - tp->tx_ring[entry].status = cpu_to_le32(DescOwned); - wmb(); - - tp->cur_tx++; - - /* Trigger an immediate transmit demand. */ - iowrite32(0, tp->base_addr + CSR1); - - spin_unlock_irqrestore(&tp->lock, flags); - - return NETDEV_TX_OK; -} - -static void tulip_clean_tx_ring(struct tulip_private *tp) -{ - unsigned int dirty_tx; - - for (dirty_tx = tp->dirty_tx ; tp->cur_tx - dirty_tx > 0; - dirty_tx++) { - int entry = dirty_tx % TX_RING_SIZE; - int status = le32_to_cpu(tp->tx_ring[entry].status); - - if (status < 0) { - tp->stats.tx_errors++; /* It wasn't Txed */ - tp->tx_ring[entry].status = 0; - } - - dma_unmap_single(&tp->pdev->dev, tp->tx_buffers[entry].mapping, - tp->tx_buffers[entry].skb->len, - DMA_TO_DEVICE); - - /* Free the original skb. */ - dev_kfree_skb_irq(tp->tx_buffers[entry].skb); - tp->tx_buffers[entry].skb = NULL; - tp->tx_buffers[entry].mapping = 0; - } -} - -static void tulip_down (struct net_device *dev) -{ - struct tulip_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->base_addr; - unsigned long flags; - - napi_disable(&tp->napi); - del_timer_sync (&tp->oom_timer); - spin_lock_irqsave (&tp->lock, flags); - - /* Disable interrupts by clearing the interrupt mask. */ - iowrite32 (0x00000000, ioaddr + CSR7); - - /* Stop the Tx and Rx processes. */ - tulip_stop_rxtx(tp); - - /* prepare receive buffers */ - tulip_refill_rx(dev); - - /* release any unconsumed transmit buffers */ - tulip_clean_tx_ring(tp); - - if (ioread32 (ioaddr + CSR6) != 0xffffffff) - tp->stats.rx_missed_errors += ioread32 (ioaddr + CSR8) & 0xffff; - - spin_unlock_irqrestore (&tp->lock, flags); -} - -static void tulip_free_ring (struct net_device *dev) -{ - struct tulip_private *tp = netdev_priv(dev); - int i; - - /* Free all the skbuffs in the Rx queue. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = tp->rx_buffers[i].skb; - dma_addr_t mapping = tp->rx_buffers[i].mapping; - - tp->rx_buffers[i].skb = NULL; - tp->rx_buffers[i].mapping = 0; - - tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */ - tp->rx_ring[i].length = 0; - /* An invalid address. */ - tp->rx_ring[i].buffer1 = cpu_to_le32(0xBADF00D0); - if (skb) { - dma_unmap_single(&tp->pdev->dev, mapping, PKT_BUF_SZ, - DMA_FROM_DEVICE); - dev_kfree_skb (skb); - } - } - - for (i = 0; i < TX_RING_SIZE; i++) { - struct sk_buff *skb = tp->tx_buffers[i].skb; - - if (skb != NULL) { - dma_unmap_single(&tp->pdev->dev, - tp->tx_buffers[i].mapping, skb->len, DMA_TO_DEVICE); - dev_kfree_skb (skb); - } - tp->tx_buffers[i].skb = NULL; - tp->tx_buffers[i].mapping = 0; - } -} - -static int tulip_close (struct net_device *dev) -{ - struct tulip_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->base_addr; - - netif_stop_queue (dev); - - tulip_down (dev); - - if (tulip_debug > 1) - dev_printk(KERN_DEBUG, &dev->dev, - "Shutting down ethercard, status was %02x\n", - ioread32 (ioaddr + CSR5)); - - free_irq (dev->irq, dev); - - tulip_free_ring (dev); - - return 0; -} - -static struct net_device_stats *tulip_get_stats(struct net_device *dev) -{ - struct tulip_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->base_addr; - - if (netif_running(dev)) { - unsigned long flags; - - spin_lock_irqsave (&tp->lock, flags); - - tp->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff; - - spin_unlock_irqrestore(&tp->lock, flags); - } - - return &tp->stats; -} - - -static void tulip_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - strcpy(info->driver, DRV_NAME); - strcpy(info->version, DRV_VERSION); - strcpy(info->bus_info, "mmio"); -} - -static const struct ethtool_ops ops = { - .get_drvinfo = tulip_get_drvinfo -}; - -static void set_rx_mode(struct net_device *dev) -{ - struct tulip_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->base_addr; - int csr6; - - csr6 = ioread32(ioaddr + CSR6) & ~0x00D5; - - tp->csr6 &= ~0x00D5; - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - tp->csr6 |= AcceptAllMulticast | AcceptAllPhys; - csr6 |= AcceptAllMulticast | AcceptAllPhys; - } else if ((netdev_mc_count(dev) > 1000) || - (dev->flags & IFF_ALLMULTI)) { - /* Too many to filter well -- accept all multicasts. */ - tp->csr6 |= AcceptAllMulticast; - csr6 |= AcceptAllMulticast; - } else { - /* Some work-alikes have only a 64-entry hash filter table. */ - /* Should verify correctness on big-endian/__powerpc__ */ - struct netdev_hw_addr *ha; - if (netdev_mc_count(dev) > 64) { - /* Arbitrary non-effective limit. */ - tp->csr6 |= AcceptAllMulticast; - csr6 |= AcceptAllMulticast; - } else { - u32 mc_filter[2] = {0, 0}; /* Multicast hash filter */ - int filterbit; - netdev_for_each_mc_addr(ha, dev) { - filterbit = ether_crc_le(ETH_ALEN, ha->addr); - filterbit &= 0x3f; - mc_filter[filterbit >> 5] |= 1 << (filterbit & 31); - if (tulip_debug > 2) - dev_info(&dev->dev, - "Added filter for %pM %08x bit %d\n", - ha->addr, - ether_crc(ETH_ALEN, ha->addr), - filterbit); - } - if (mc_filter[0] == tp->mc_filter[0] && - mc_filter[1] == tp->mc_filter[1]) - ; /* No change. */ - iowrite32(mc_filter[0], ioaddr + CSR27); - iowrite32(mc_filter[1], ioaddr + CSR28); - tp->mc_filter[0] = mc_filter[0]; - tp->mc_filter[1] = mc_filter[1]; - } - } - - if (dev->irq == ADM8668_LAN_IRQ) - csr6 |= (1 << 9); /* force 100Mbps full duplex */ -// csr6 |= 1; /* pad 2 bytes. vlan? */ - - iowrite32(csr6, ioaddr + CSR6); -} - -static const struct net_device_ops tulip_netdev_ops = { - .ndo_open = tulip_open, - .ndo_start_xmit = tulip_start_xmit, - .ndo_tx_timeout = tulip_tx_timeout, - .ndo_stop = tulip_close, - .ndo_get_stats = tulip_get_stats, - .ndo_set_rx_mode = set_rx_mode, - .ndo_change_mtu = eth_change_mtu, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = poll_tulip, -#endif -}; - -static int __devinit adm8668net_probe(struct platform_device *pdev) -{ - struct tulip_private *tp; - struct net_device *dev; - struct resource *res; - void __iomem *ioaddr; - int irq; - - if (pdev->id < 0 || pdev->id >= MAX_UNITS) - return -EINVAL; - - if (!(res = platform_get_resource(pdev, IORESOURCE_IRQ, 0))) - return -ENODEV; - irq = res->start; - if (!(res = platform_get_resource(pdev, IORESOURCE_MEM, 0))) - return -ENODEV; - if (!(ioaddr = ioremap(res->start, res->end - res->start))) - return -ENODEV; - if (!(dev = alloc_etherdev(sizeof (*tp)))) - return -ENOMEM; - - /* setup net dev */ - dev->base_addr = (unsigned long)res->start; - dev->irq = irq; - SET_NETDEV_DEV(dev, &pdev->dev); - - /* tulip private struct */ - tp = netdev_priv(dev); - tp->dev = dev; - tp->base_addr = ioaddr; - tp->csr0 = csr0; - tp->pdev = pdev; - tp->rx_ring = dma_alloc_coherent(&pdev->dev, - sizeof(struct tulip_rx_desc) * RX_RING_SIZE + - sizeof(struct tulip_tx_desc) * TX_RING_SIZE, - &tp->rx_ring_dma, GFP_KERNEL); - if (!tp->rx_ring) - return -ENODEV; - tp->tx_ring = (struct tulip_tx_desc *)(tp->rx_ring + RX_RING_SIZE); - tp->tx_ring_dma = tp->rx_ring_dma + sizeof(struct tulip_rx_desc) * RX_RING_SIZE; - - spin_lock_init(&tp->lock); - - /* Stop the chip's Tx and Rx processes. */ - tulip_stop_rxtx(tp); - - /* Clear the missed-packet counter. */ - ioread32(ioaddr + CSR8); - - /* Addresses are stored in BSP area of NOR flash */ - if (irq == ADM8668_WAN_IRQ) - memcpy(dev->dev_addr, (char *)ADM8668_WAN_MACADDR, 6); - else - memcpy(dev->dev_addr, (char *)ADM8668_LAN_MACADDR, 6); - - /* The Tulip-specific entries in the device structure. */ - dev->netdev_ops = &tulip_netdev_ops; - dev->watchdog_timeo = TX_TIMEOUT; - netif_napi_add(dev, &tp->napi, tulip_poll, 16); - SET_ETHTOOL_OPS(dev, &ops); - - if (register_netdev(dev)) - goto err_out_free_ring; - - dev_info(&dev->dev, - "ADM8668net at MMIO %#lx %pM, IRQ %d\n", - (unsigned long)dev->base_addr, dev->dev_addr, irq); - - platform_set_drvdata(pdev, dev); - return 0; - -err_out_free_ring: - dma_free_coherent(&pdev->dev, - sizeof (struct tulip_rx_desc) * RX_RING_SIZE + - sizeof (struct tulip_tx_desc) * TX_RING_SIZE, - tp->rx_ring, tp->rx_ring_dma); - return -ENODEV; -} - -static int __devexit adm8668net_remove(struct platform_device *pdev) -{ - struct net_device *dev = platform_get_drvdata (pdev); - struct tulip_private *tp; - - if (!dev) - return -ENODEV; - - tp = netdev_priv(dev); - unregister_netdev(dev); - dma_free_coherent(&pdev->dev, - sizeof (struct tulip_rx_desc) * RX_RING_SIZE + - sizeof (struct tulip_tx_desc) * TX_RING_SIZE, - tp->rx_ring, tp->rx_ring_dma); - iounmap(tp->base_addr); - free_netdev(dev); - platform_set_drvdata(pdev, NULL); - return 0; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -/* - * Polling 'interrupt' - used by things like netconsole to send skbs - * without having to re-enable interrupts. It's not called while - * the interrupt routine is executing. - */ - -static void poll_tulip (struct net_device *dev) -{ - /* disable_irq here is not very nice, but with the lockless - interrupt handler we have no other choice. */ - disable_irq(dev->irq); - tulip_interrupt(dev->irq, dev); - enable_irq(dev->irq); -} -#endif - -static struct platform_driver adm8668net_platform_driver = { - .probe = adm8668net_probe, - .remove = __devexit_p(adm8668net_remove), - .driver = { - .owner = THIS_MODULE, - .name = "adm8668_eth" - }, -}; - -static int __init adm8668net_init(void) -{ - pr_info("%s", version); - return platform_driver_register(&adm8668net_platform_driver); -} - -static void __exit adm8668net_exit(void) -{ - platform_driver_unregister(&adm8668net_platform_driver); -} - -module_init(adm8668net_init); -module_exit(adm8668net_exit); diff --git a/target/linux/adm8668/files/arch/mips/adm8668/net_intr.c b/target/linux/adm8668/files/arch/mips/adm8668/net_intr.c deleted file mode 100644 index 113dbaebd..000000000 --- a/target/linux/adm8668/files/arch/mips/adm8668/net_intr.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * originally drivers/net/tulip/interrupt.c - * Copyright 2000,2001 The Linux Kernel Team - * Written/copyright 1994-2001 by Donald Becker. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include "net.h" - -int tulip_refill_rx(struct net_device *dev) -{ - struct tulip_private *tp = netdev_priv(dev); - int entry; - int refilled = 0; - - /* Refill the Rx ring buffers. */ - for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) { - entry = tp->dirty_rx % RX_RING_SIZE; - if (tp->rx_buffers[entry].skb == NULL) { - struct sk_buff *skb; - dma_addr_t mapping; - - skb = tp->rx_buffers[entry].skb = dev_alloc_skb(PKT_BUF_SZ); - if (skb == NULL) - break; - - mapping = dma_map_single(&dev->dev, skb->data, - PKT_BUF_SZ, DMA_FROM_DEVICE); - tp->rx_buffers[entry].mapping = mapping; - - skb->dev = dev; /* Mark as being used by this device. */ - tp->rx_ring[entry].buffer1 = cpu_to_le32(mapping); - refilled++; - } - tp->rx_ring[entry].status = cpu_to_le32(DescOwned); - } - return refilled; -} - -void oom_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = netdev_priv(dev); - napi_schedule(&tp->napi); -} - -int tulip_poll(struct napi_struct *napi, int budget) -{ - struct tulip_private *tp = container_of(napi, struct tulip_private, napi); - struct net_device *dev = tp->dev; - int entry = tp->cur_rx % RX_RING_SIZE; - int work_done = 0; - - if (tulip_debug > 4) - printk(KERN_DEBUG " In tulip_rx(), entry %d %08x\n", - entry, tp->rx_ring[entry].status); - - do { - if (ioread32(tp->base_addr + CSR5) == 0xffffffff) { - printk(KERN_DEBUG " In tulip_poll(), hardware disappeared\n"); - break; - } - /* Acknowledge current RX interrupt sources. */ - iowrite32((RxIntr | RxNoBuf), tp->base_addr + CSR5); - - - /* If we own the next entry, it is a new packet. Send it up. */ - while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) { - s32 status = le32_to_cpu(tp->rx_ring[entry].status); - short pkt_len; - - if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx) - break; - - if (tulip_debug > 5) - printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %08x\n", - dev->name, entry, status); - - if (++work_done >= budget) - goto not_done; - - /* - * Omit the four octet CRC from the length. - * (May not be considered valid until we have - * checked status for RxLengthOver2047 bits) - */ - pkt_len = ((status >> 16) & 0x7ff) - 4; - -#if 0 - csr6 = ioread32(tp->base_addr + CSR6); - if (csr6 & 0x1) - pkt_len += 2; - -#endif - /* - * Maximum pkt_len is 1518 (1514 + vlan header) - * Anything higher than this is always invalid - * regardless of RxLengthOver2047 bits - */ - - if ((status & (RxLengthOver2047 | - RxDescCRCError | - RxDescCollisionSeen | - RxDescRunt | - RxDescDescErr | - RxWholePkt)) != RxWholePkt || - pkt_len > 1518) { - if ((status & (RxLengthOver2047 | - RxWholePkt)) != RxWholePkt) { - /* Ingore earlier buffers. */ - if ((status & 0xffff) != 0x7fff) { - if (tulip_debug > 1) - dev_warn(&dev->dev, - "Oversized Ethernet frame spanned multiple buffers, status %08x!\n", - status); - tp->stats.rx_length_errors++; - } - } else { - /* There was a fatal error. */ - if (tulip_debug > 2) - printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n", - dev->name, status); - tp->stats.rx_errors++; /* end of a packet.*/ - if (pkt_len > 1518 || - (status & RxDescRunt)) - tp->stats.rx_length_errors++; - - if (status & 0x0004) tp->stats.rx_frame_errors++; - if (status & 0x0002) tp->stats.rx_crc_errors++; - if (status & 0x0001) tp->stats.rx_fifo_errors++; - } - } else { - struct sk_buff *skb = tp->rx_buffers[entry].skb; - char *temp = skb_put(skb, pkt_len); - -#if 0 - if (csr6 & 1) - skb_pull(skb, 2); -#endif -#ifndef final_version - if (tp->rx_buffers[entry].mapping != - le32_to_cpu(tp->rx_ring[entry].buffer1)) { - dev_err(&dev->dev, - "Internal fault: The skbuff addresses do not match in tulip_rx: %08x vs. %08llx %p / %p\n", - le32_to_cpu(tp->rx_ring[entry].buffer1), - (unsigned long long)tp->rx_buffers[entry].mapping, - skb->head, temp); - } -#endif - - tp->rx_buffers[entry].skb = NULL; - tp->rx_buffers[entry].mapping = 0; - skb->protocol = eth_type_trans(skb, dev); - - netif_receive_skb(skb); - - tp->stats.rx_packets++; - tp->stats.rx_bytes += pkt_len; - } - entry = (++tp->cur_rx) % RX_RING_SIZE; - if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4) - tulip_refill_rx(dev); - - } - - /* New ack strategy... irq does not ack Rx any longer - hopefully this helps */ - - /* Really bad things can happen here... If new packet arrives - * and an irq arrives (tx or just due to occasionally unset - * mask), it will be acked by irq handler, but new thread - * is not scheduled. It is major hole in design. - * No idea how to fix this if "playing with fire" will fail - * tomorrow (night 011029). If it will not fail, we won - * finally: amount of IO did not increase at all. */ - } while ((ioread32(tp->base_addr + CSR5) & RxIntr)); - - tulip_refill_rx(dev); - - /* If RX ring is not full we are out of memory. */ - if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) - goto oom; - - /* Remove us from polling list and enable RX intr. */ - napi_complete(napi); - iowrite32(VALID_INTR, tp->base_addr+CSR7); - - /* The last op happens after poll completion. Which means the following: - * 1. it can race with disabling irqs in irq handler - * 2. it can race with dise/enabling irqs in other poll threads - * 3. if an irq raised after beginning loop, it will be immediately - * triggered here. - * - * Summarizing: the logic results in some redundant irqs both - * due to races in masking and due to too late acking of already - * processed irqs. But it must not result in losing events. - */ - - return work_done; - - not_done: - if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 || - tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) - tulip_refill_rx(dev); - - if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) - goto oom; - - return work_done; - - oom: /* Executed with RX ints disabled */ - - /* Start timer, stop polling, but do not enable rx interrupts. */ - mod_timer(&tp->oom_timer, jiffies+1); - - /* Think: timer_pending() was an explicit signature of bug. - * Timer can be pending now but fired and completed - * before we did napi_complete(). See? We would lose it. */ - - /* remove ourselves from the polling list */ - napi_complete(napi); - - return work_done; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -irqreturn_t tulip_interrupt(int irq, void *dev_instance) -{ - struct net_device *dev = (struct net_device *)dev_instance; - struct tulip_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->base_addr; - int csr5; - int missed; - int rx = 0; - int tx = 0; - int oi = 0; - int maxrx = RX_RING_SIZE; - int maxtx = TX_RING_SIZE; - int maxoi = TX_RING_SIZE; - int rxd = 0; - unsigned int work_count = 25; - unsigned int handled = 0; - - /* Let's see whether the interrupt really is for us */ - csr5 = ioread32(ioaddr + CSR5); - - if ((csr5 & (NormalIntr|AbnormalIntr)) == 0) - return IRQ_RETVAL(handled); - - tp->nir++; - - do { - - if (!rxd && (csr5 & (RxIntr | RxNoBuf))) { - rxd++; - /* Mask RX intrs and add the device to poll list. */ - iowrite32(VALID_INTR&~RxPollInt, ioaddr + CSR7); - napi_schedule(&tp->napi); - - if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) - break; - } - - /* Acknowledge the interrupt sources we handle here ASAP - the poll function does Rx and RxNoBuf acking */ - - iowrite32(csr5 & 0x0001ff3f, ioaddr + CSR5); - - if (tulip_debug > 4) - printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x\n", - dev->name, csr5, ioread32(ioaddr + CSR5)); - - - if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) { - unsigned int dirty_tx; - - spin_lock(&tp->lock); - - for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0; - dirty_tx++) { - int entry = dirty_tx % TX_RING_SIZE; - int status = le32_to_cpu(tp->tx_ring[entry].status); - - if (status < 0) - break; /* It still has not been Txed */ - - if (status & 0x8000) { - /* There was an major error, log it. */ -#ifndef final_version - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n", - dev->name, status); -#endif - tp->stats.tx_errors++; - if (status & 0x4104) tp->stats.tx_aborted_errors++; - if (status & 0x0C00) tp->stats.tx_carrier_errors++; - if (status & 0x0200) tp->stats.tx_window_errors++; - if (status & 0x0002) tp->stats.tx_fifo_errors++; - if (status & 0x0080) tp->stats.tx_heartbeat_errors++; - } else { - tp->stats.tx_bytes += - tp->tx_buffers[entry].skb->len; - tp->stats.collisions += (status >> 3) & 15; - tp->stats.tx_packets++; - } - - dma_unmap_single(&tp->pdev->dev, tp->tx_buffers[entry].mapping, - tp->tx_buffers[entry].skb->len, DMA_TO_DEVICE); - /* Free the original skb. */ - dev_kfree_skb_irq(tp->tx_buffers[entry].skb); - tp->tx_buffers[entry].skb = NULL; - tp->tx_buffers[entry].mapping = 0; - tx++; - } - -#ifndef final_version - if (tp->cur_tx - dirty_tx > TX_RING_SIZE) { - dev_err(&dev->dev, - "Out-of-sync dirty pointer, %d vs. %d\n", - dirty_tx, tp->cur_tx); - dirty_tx += TX_RING_SIZE; - } -#endif - - if (tp->cur_tx - dirty_tx < TX_RING_SIZE - 2) - netif_wake_queue(dev); - - tp->dirty_tx = dirty_tx; - if (csr5 & TxDied) { - if (tulip_debug > 2) - dev_warn(&dev->dev, - "The transmitter stopped. CSR5 is %x, CSR6 %x, new CSR6 %x\n", - csr5, ioread32(ioaddr + CSR6), - tp->csr6); - tulip_restart_rxtx(tp); - } - spin_unlock(&tp->lock); - } - - /* Log errors. */ - if (csr5 & AbnormalIntr) { /* Abnormal error summary bit. */ - if (csr5 == 0xffffffff) - break; - if (csr5 & TxJabber) tp->stats.tx_errors++; - if (csr5 & TxFIFOUnderflow) { - if ((tp->csr6 & 0xC000) != 0xC000) - tp->csr6 += 0x4000; /* Bump up the Tx threshold */ - else - tp->csr6 |= 0x00200000; /* Store-n-forward. */ - /* Restart the transmit process. */ - tulip_restart_rxtx(tp); - iowrite32(0, ioaddr + CSR1); - } - if (csr5 & (RxDied | RxNoBuf)) { - iowrite32(tp->mc_filter[0], ioaddr + CSR27); - iowrite32(tp->mc_filter[1], ioaddr + CSR28); - } - if (csr5 & RxDied) { /* Missed a Rx frame. */ - tp->stats.rx_missed_errors += ioread32(ioaddr + CSR8) & 0xffff; - tp->stats.rx_errors++; - tulip_start_rxtx(tp); - } - /* - * NB: t21142_lnk_change() does a del_timer_sync(), so be careful if this - * call is ever done under the spinlock - */ - if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { - if (tp->link_change) - (tp->link_change)(dev, csr5); - } - if (csr5 & SystemError) { - int error = (csr5 >> 23) & 7; - /* oops, we hit a PCI error. The code produced corresponds - * to the reason: - * 0 - parity error - * 1 - master abort - * 2 - target abort - * Note that on parity error, we should do a software reset - * of the chip to get it back into a sane state (according - * to the 21142/3 docs that is). - * -- rmk - */ - dev_err(&dev->dev, - "(%lu) System Error occurred (%d)\n", - tp->nir, error); - } - /* Clear all error sources, included undocumented ones! */ - iowrite32(0x0800f7ba, ioaddr + CSR5); - oi++; - } - if (csr5 & TimerInt) { - - if (tulip_debug > 2) - dev_err(&dev->dev, - "Re-enabling interrupts, %08x\n", - csr5); - iowrite32(VALID_INTR, ioaddr + CSR7); - oi++; - } - if (tx > maxtx || rx > maxrx || oi > maxoi) { - if (tulip_debug > 1) - dev_warn(&dev->dev, "Too much work during an interrupt, csr5=0x%08x. (%lu) (%d,%d,%d)\n", - csr5, tp->nir, tx, rx, oi); - - /* Acknowledge all interrupt sources. */ - iowrite32(0x8001ffff, ioaddr + CSR5); - /* Mask all interrupting sources, set timer to - re-enable. */ - iowrite32(((~csr5) & 0x0001ebef) | AbnormalIntr | TimerInt, ioaddr + CSR7); - iowrite32(0x0012, ioaddr + CSR11); - break; - } - - work_count--; - if (work_count == 0) - break; - - csr5 = ioread32(ioaddr + CSR5); - - if (rxd) - csr5 &= ~RxPollInt; - } while ((csr5 & (TxNoBuf | - TxDied | - TxIntr | - TimerInt | - /* Abnormal intr. */ - RxDied | - TxFIFOUnderflow | - TxJabber | - TPLnkFail | - SystemError )) != 0); - - if ((missed = ioread32(ioaddr + CSR8) & 0x1ffff)) { - tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed; - } - - if (tulip_debug > 4) - printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#04x\n", - dev->name, ioread32(ioaddr + CSR5)); - - return IRQ_HANDLED; -} diff --git a/target/linux/adm8668/files/arch/mips/adm8668/pci.c b/target/linux/adm8668/files/arch/mips/adm8668/pci.c deleted file mode 100644 index 2bf119297..000000000 --- a/target/linux/adm8668/files/arch/mips/adm8668/pci.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/types.h> -#include <asm/byteorder.h> -#include <asm/pci.h> -#include <adm8668.h> - -volatile u32* pci_config_address_reg = (volatile u32*)KSEG1ADDR(PCICFG_BASE); -volatile u32* pci_config_data_reg = (volatile u32*)KSEG1ADDR(PCIDAT_BASE); - -#define PCI_ENABLE 0x80000000 -#define ADMPCI_IO_BASE 0x12600000 -#define ADMPCI_IO_SIZE 0x1fffff -#define ADMPCI_MEM_BASE 0x16000000 -#define ADMPCI_MEM_SIZE 0x7ffffff -#define PCI_CMM_IOACC_EN 0x1 -#define PCI_CMM_MEMACC_EN 0x2 -#define PCI_CMM_MASTER_EN 0x4 -#define PCI_CMM_DEF (PCI_CMM_IOACC_EN | PCI_CMM_MEMACC_EN | PCI_CMM_MASTER_EN) - -#define PCI_DEF_CACHE_LINE_SZ 0 -#define PCI_DEF_LATENCY_TIMER 0x20 -#define PCI_DEF_CACHE_LATENCY ((PCI_DEF_LATENCY_TIMER << 8) | PCI_DEF_CACHE_LINE_SZ) - - -#define cfgaddr(bus, devfn, where) ( \ - (bus ? ((bus->number & 0xff) << 0x10) : 0) | \ - ((devfn & 0xff) << 0x08) | \ - (where & 0xfc)) | PCI_ENABLE - -/* assumed little endian */ -static int adm8668_read_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *val) -{ - switch (size) - { - case 1: - *pci_config_address_reg = cfgaddr(bus, devfn, where); - *val = (le32_to_cpu(*pci_config_data_reg) >> ((where&3)<<3)) & 0xff; - break; - case 2: - if (where & 1) - return PCIBIOS_BAD_REGISTER_NUMBER; - *pci_config_address_reg = cfgaddr(bus, devfn, where); - *val = (le32_to_cpu(*pci_config_data_reg) >> ((where&3)<<3)) & 0xffff; - break; - case 4: - if (where & 3) - return PCIBIOS_BAD_REGISTER_NUMBER; - *pci_config_address_reg = cfgaddr(bus, devfn, where); - *val = le32_to_cpu(*pci_config_data_reg); - break; - } - - return PCIBIOS_SUCCESSFUL; -} - -static int adm8668_write_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val) -{ - switch (size) - { - case 1: - *pci_config_address_reg = cfgaddr(bus, devfn, where); - *(volatile u8 *)(((int)pci_config_data_reg) + (where & 3)) = val; - break; - case 2: - if (where & 1) - return PCIBIOS_BAD_REGISTER_NUMBER; - *pci_config_address_reg = cfgaddr(bus, devfn, where); - *(volatile u16 *)(((int)pci_config_data_reg) + (where & 2)) = val; - break; - case 4: - if (where & 3) - return PCIBIOS_BAD_REGISTER_NUMBER; - *pci_config_address_reg = cfgaddr(bus, devfn, where); - *pci_config_data_reg = (val); - } - - return PCIBIOS_SUCCESSFUL; -} - - -struct pci_ops adm8668_pci_ops = { - .read = adm8668_read_config, - .write = adm8668_write_config -}; - - -struct resource pciioport_resource = { - .name = "adm8668_pci", - .start = ADMPCI_IO_BASE, - .end = ADMPCI_IO_BASE + ADMPCI_IO_SIZE, - .flags = IORESOURCE_IO -}; - - -struct resource pciiomem_resource = { - .name = "adm8668_pci", - .start = ADMPCI_MEM_BASE, - .end = ADMPCI_MEM_BASE + ADMPCI_MEM_SIZE, - .flags = IORESOURCE_MEM -}; - -#ifdef CONFIG_ADM8668_DISABLE_PCI -struct pci_controller mips_pci_channels[] = { - { NULL, NULL, NULL , NULL , NULL} -}; -#else -struct pci_controller mips_pci_channels = { - .pci_ops = &adm8668_pci_ops, - .io_resource = &pciioport_resource, - .mem_resource = &pciiomem_resource, -}; -#endif - -int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - switch (slot) - { - case 1: - return 14; - case 2: - return 13; - case 3: - return 12; - default: - return dev->irq; - } -} - -int pcibios_plat_dev_init(struct pci_dev *dev) -{ - return 0; -} - -static int __init adm8668_pci_init(void) -{ - void __iomem *io_map_base; - - printk("adm8668_pci_init()\n"); - - /* what's an io port? this is MIPS... *shrug* */ - ioport_resource.start = ADMPCI_IO_BASE; - ioport_resource.end = ADMPCI_IO_BASE + ADMPCI_IO_SIZE; - - io_map_base = ioremap(ADMPCI_IO_BASE, ADMPCI_IO_SIZE); - if (!io_map_base) - printk("io_map_base didn't work.\n"); - mips_pci_channels.io_map_base = (unsigned long)io_map_base; - register_pci_controller(&mips_pci_channels); - - /* this needed? linksys' gpl 2.4 did it... */ - adm8668_write_config(NULL, 0, PCI_CACHE_LINE_SIZE, 2, 0); - adm8668_write_config(NULL, 0, PCI_BASE_ADDRESS_0, 4, 0); - adm8668_write_config(NULL, 0, PCI_BASE_ADDRESS_1, 4, 0); - adm8668_write_config(NULL, 0, PCI_COMMAND, 4, PCI_CMM_DEF); - - return 0; -} - -arch_initcall(adm8668_pci_init); diff --git a/target/linux/adm8668/files/arch/mips/adm8668/platform.c b/target/linux/adm8668/files/arch/mips/adm8668/platform.c index 803af09aa..7cd56b787 100644 --- a/target/linux/adm8668/files/arch/mips/adm8668/platform.c +++ b/target/linux/adm8668/files/arch/mips/adm8668/platform.c @@ -1,5 +1,8 @@ /* + * Infineon/ADMTek 8668 (WildPass) platform devices support + * * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> + * Copyright (C) 2012 Florian Fainelli <florian@openwrt.org> * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -9,10 +12,16 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/platform_device.h> +#include <linux/platform_data/tulip.h> +#include <linux/usb/ehci_pdriver.h> #include <linux/mtd/physmap.h> +#include <linux/mtd/partitions.h> #include <linux/pci.h> #include <linux/slab.h> #include <linux/ioport.h> +#include <linux/amba/bus.h> +#include <linux/amba/serial.h> + #include <asm/reboot.h> #include <asm/time.h> #include <asm/addrspace.h> @@ -20,23 +29,35 @@ #include <asm/io.h> #include <adm8668.h> -static struct resource uart_resources[] = { - { +#define ADM8868_UBOOT_ENV 0x20000 +#define ADM8868_UBOOT_WAN_MAC 0x5ac +#define ADM8868_UBOOT_LAN_MAC 0x404 + +static void adm8668_uart_set_mctrl(struct amba_device *dev, + void __iomem *base, + unsigned int mcrtl) +{ +} + +static struct amba_pl010_data adm8668_uart0_data = { + .set_mctrl = adm8668_uart_set_mctrl, +}; + +static struct amba_device adm8668_uart0_device = { + .dev = { + .init_name = "apb:uart0", + .platform_data = &adm8668_uart0_data, + }, + .res = { .start = ADM8668_UART0_BASE, .end = ADM8668_UART0_BASE + 0xF, .flags = IORESOURCE_MEM, }, - { - .start = INT_LVL_UART0, - .flags = IORESOURCE_IRQ, + .irq = { + ADM8668_UART0_IRQ, + -1 }, -}; - -static struct platform_device adm8668_uart_device = { - .name = "adm8668_uart", - .id = 0, - .resource = uart_resources, - .num_resources = ARRAY_SIZE(uart_resources), + .periphid = 0x0041010, }; static struct resource eth0_resources[] = { @@ -46,16 +67,21 @@ static struct resource eth0_resources[] = { .flags = IORESOURCE_MEM, }, { - .start = INT_LVL_LAN, + .start = ADM8668_LAN_IRQ, .flags = IORESOURCE_IRQ, }, }; +static struct tulip_platform_data eth0_pdata = { + .chip_id = ADM8668, +}; + static struct platform_device adm8668_eth0_device = { - .name = "adm8668_eth", + .name = "tulip", .id = 0, .resource = eth0_resources, .num_resources = ARRAY_SIZE(eth0_resources), + .dev.platform_data = ð0_pdata, }; static struct resource eth1_resources[] = { @@ -65,87 +91,134 @@ static struct resource eth1_resources[] = { .flags = IORESOURCE_MEM, }, { - .start = INT_LVL_WAN, + .start = ADM8668_WAN_IRQ, .flags = IORESOURCE_IRQ, }, }; +static struct tulip_platform_data eth1_pdata = { + .chip_id = ADM8668, +}; + static struct platform_device adm8668_eth1_device = { - .name = "adm8668_eth", + .name = "tulip", .id = 1, .resource = eth1_resources, .num_resources = ARRAY_SIZE(eth1_resources), + .dev.platform_data = ð1_pdata, }; -static void adm8668_restart(char *cmd) -{ - int i; - - /* stop eth0 and eth1 */ - ADM8668_LAN_REG(NETCSR6) = (1 << 13) | (1 << 1); - ADM8668_LAN_REG(NETCSR7) = 0; - ADM8668_WAN_REG(NETCSR6) = (1 << 13) | (1 << 1); - ADM8668_WAN_REG(NETCSR7) = 0; - - /* reset PHY */ - ADM8668_WAN_REG(NETCSR37) = 0x20; - for (i = 0; i < 10000; i++) - ; - ADM8668_WAN_REG(NETCSR37) = 0; - for (i = 0; i < 10000; i++) - ; - - *(volatile unsigned int *)0xB1600000 = 1; /* reset eth0 mac */ - *(volatile unsigned int *)0xB1A00000 = 1; /* reset eth1 mac */ - *(volatile unsigned int *)0xB1800000 = 1; /* reset wlan0 mac */ - - /* the real deal */ - for (i = 0; i < 1000; i++) - ; - ADM8668_CONFIG_REG(ADM8668_CR1) = 1; -} +static const char *nor_probe_types[] = { "adm8668part", NULL }; -int __devinit adm8668_devs_register(void) -{ - _machine_restart = adm8668_restart; - platform_device_register(&adm8668_uart_device); - platform_device_register(&adm8668_eth0_device); - platform_device_register(&adm8668_eth1_device); +static struct physmap_flash_data nor_flash_data = { + .width = 2, + .part_probe_types = nor_probe_types, +}; - return 0; -} +static struct resource nor_resources[] = { + { + .start = ADM8668_SMEM1_BASE, + .end = ADM8668_SMEM1_BASE + 0x800000 - 1, + .flags = IORESOURCE_MEM, + }, +}; -void __init plat_time_init(void) -{ - int adj = (ADM8668_CONFIG_REG(ADM8668_CR3) >> 11) & 0xf; +static struct platform_device adm8668_nor_device = { + .name = "physmap-flash", + .id = -1, + .resource = nor_resources, + .num_resources = ARRAY_SIZE(nor_resources), + .dev.platform_data = &nor_flash_data, +}; - /* adjustable clock selection - CR3 bit 14~11, 0000 -> 175MHz, 0001 -> 180MHz, etc... */ +static struct resource usb_resources[] = { + { + .start = ADM8668_USB_BASE, + .end = ADM8668_USB_BASE + 0x1FFFFF, + .flags = IORESOURCE_MEM, + }, + { + .start = ADM8668_USB_IRQ, + .end = ADM8668_USB_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; - mips_hpt_frequency = (SYS_CLOCK + adj * 5000000) / 2; - printk("ADM8668 CPU clock: %d MHz\n", 2*mips_hpt_frequency / 1000000); -} +static struct usb_ehci_pdata usb_pdata = { + .caps_offset = 0x100, + .has_tt = 1, + .port_power_off = 1, +}; + +static struct platform_device adm8668_usb_device = { + .name = "ehci-platform", + .id = -1, + .resource = usb_resources, + .num_resources = ARRAY_SIZE(usb_resources), + .dev.platform_data = &usb_pdata, +}; -void __init plat_mem_setup(void) +static struct platform_device *adm8668_devs[] = { + &adm8668_eth0_device, + &adm8668_eth1_device, + &adm8668_nor_device, + &adm8668_usb_device, +}; + +static void adm8668_fetch_mac(int unit) { - /* prom_init seemed like easier place for this. it's tooo simple */ + u8 *mac; + u32 offset; + struct tulip_platform_data *pdata; + + switch (unit) { + case -1: + case 0: + offset = ADM8868_UBOOT_LAN_MAC; + pdata = ð0_pdata; + break; + case 1: + offset = ADM8868_UBOOT_WAN_MAC; + pdata = ð1_pdata; + break; + default: + pr_err("unsupported ethernet unit: %d\n", unit); + return; + } + + mac = (u8 *)(KSEG1ADDR(ADM8668_SMEM1_BASE) + ADM8868_UBOOT_ENV + offset); + + memcpy(pdata->mac, mac, sizeof(pdata->mac)); } -const char *get_system_type(void) +static void adm8668_ehci_workaround(void) { - unsigned long chipid = ADM8668_CONFIG_REG(ADM8668_CR0); - int adj = (ADM8668_CONFIG_REG(ADM8668_CR3) >> 11) & 0xf; - int product, revision, mhz; - static char ret[32]; + u32 chipid; - product = chipid >> 16; - revision = chipid & 0xffff; - mhz = (SYS_CLOCK/1000000) + (adj * 5); + chipid = ADM8668_CONFIG_REG(ADM8668_CR0); + ADM8668_CONFIG_REG(ADM8668_CR66) = 0x0C1600D9; - /* i getting fancy :\ */ - snprintf(ret, sizeof(ret), "ADM%xr%x %dMHz", product, revision, mhz); + if (chipid == 0x86880001) + return; - return ret; + ADM8668_CONFIG_REG(ADM8668_CR66) &= ~(3 << 20); + ADM8668_CONFIG_REG(ADM8668_CR66) |= (1 << 20); + pr_info("ADM8668: applied USB workaround\n"); } + +int __devinit adm8668_devs_register(void) +{ + int ret; + + ret = amba_device_register(&adm8668_uart0_device, &iomem_resource); + if (ret) + panic("failed to register AMBA UART"); + + adm8668_fetch_mac(0); + adm8668_fetch_mac(1); + adm8668_ehci_workaround(); + + return platform_add_devices(adm8668_devs, ARRAY_SIZE(adm8668_devs)); +} arch_initcall(adm8668_devs_register); diff --git a/target/linux/adm8668/files/arch/mips/adm8668/proc.c b/target/linux/adm8668/files/arch/mips/adm8668/proc.c deleted file mode 100644 index 77dbb1faf..000000000 --- a/target/linux/adm8668/files/arch/mips/adm8668/proc.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/proc_fs.h> -#include <asm/uaccess.h> -#include <adm8668.h> - -int adm8668_sesled_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) -{ - char buf[8]; - int num; - - num = (count < 8) ? count : 8; - - if (copy_from_user(buf, buffer, num)) - { - printk("copy_from_user failed"); - return -EFAULT; - } - num = simple_strtoul(buf, NULL, 16); - switch (num) - { - case 0: - GPIO_SET_LOW(0); - CRGPIO_SET_LOW(2); - break; - case 1: - GPIO_SET_LOW(0); - CRGPIO_SET_HI(2); - break; - case 2: - GPIO_SET_HI(0); - CRGPIO_SET_HI(2); - break; - default: - break; - } - - return count; -} - -int adm8668_sesled_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *data) -{ - int len = 0; - int led_state = 0; - - led_state = (ADM8668_CONFIG_REG(CRGPIO_REG) & 0x100) ? 1 : 0; - led_state += (ADM8668_WLAN_REG(GPIO_REG) & 0x40) ? 2 : 0; - len += sprintf(buf+len, "%s\n", - (led_state&1) ? - ((led_state&2) ? "ORANGE" : "GREEN") : "OFF"); - - return len; -} - -int adm8668_button_read_proc(char *buf, char **start, off_t offset, - int count, int *eof, void *data) -{ - int len = 0; - int read_once = ADM8668_CONFIG_REG(CRGPIO_REG); - int button_flip = (read_once >> 20) & 0x3; - int button_state = read_once & 0x3; - - len += sprintf(buf+len, "SES: %s %s\nRESET: %s %s\n", - (button_state&2) ? "UP" : "DOWN", - (button_flip&2) ? "FLIP" : "", - (button_state&1) ? "UP" : "DOWN", - (button_flip&1) ? "FLIP" : ""); - - return len; -} - -int __init adm8668_init_proc(void) -{ - struct proc_dir_entry *adm8668_proc_dir = NULL; - struct proc_dir_entry *sesled = NULL; - int __maybe_unused bogus; - - /* these are known to be lights. rest are input...? */ - ADM8668_CONFIG_REG(CRGPIO_REG) = GPIO2_OUTPUT_ENABLE; - ADM8668_WLAN_REG(GPIO_REG) = GPIO0_OUTPUT_ENABLE; - - /* inital read off of the flipper switcher on the button thingie */ - bogus = ADM8668_CONFIG_REG(CRGPIO_REG); - - adm8668_proc_dir = proc_mkdir("adm8668", 0); - if (adm8668_proc_dir == NULL) { - printk(KERN_ERR "ADM8668 proc: unable to create proc dir.\n"); - return 0; - } - create_proc_read_entry("buttons", 0444, adm8668_proc_dir, - adm8668_button_read_proc, NULL); - sesled = create_proc_entry("sesled", S_IRUGO|S_IWUGO, adm8668_proc_dir); - if (sesled) { - sesled->read_proc = adm8668_sesled_read_proc; - sesled->write_proc = adm8668_sesled_write_proc; - } - - return 0; -} - -module_init(adm8668_init_proc); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Scott Nicholas <neutronscott@scottn.us>"); -MODULE_DESCRIPTION("ADM8668 ghetto button driver"); diff --git a/target/linux/adm8668/files/arch/mips/adm8668/prom.c b/target/linux/adm8668/files/arch/mips/adm8668/prom.c index 7187f2982..24b77f8b9 100644 --- a/target/linux/adm8668/files/arch/mips/adm8668/prom.c +++ b/target/linux/adm8668/files/arch/mips/adm8668/prom.c @@ -25,44 +25,6 @@ register volatile struct global_data *gd asm ("k0"); -#ifdef CONFIG_SERIAL_ADM8668_CONSOLE -static inline unsigned int adm_uart_readl(unsigned int offset) -{ - return (*(volatile unsigned int *)(0xbe400000 + offset)); -} - -static inline void adm_uart_writel(unsigned int value, unsigned int offset) -{ - (*((volatile unsigned int *)(0xbe400000 + offset))) = value; -} - -static void prom_putchar(char c) -{ - adm_uart_writel(c, UART_DR_REG); - while ((adm_uart_readl(UART_FR_REG) & UART_TX_FIFO_FULL) != 0) - ; -} - -static void __init -early_console_write(struct console *con, const char *s, unsigned n) -{ - while (n-- && *s) { - if (*s == '\n') - prom_putchar('\r'); - prom_putchar(*s); - s++; - } -} - -static struct console early_console __initdata = { - .name = "early", - .write = early_console_write, - .flags = CON_BOOT, - .index = -1 -}; - -#endif - void __init prom_free_prom_memory(void) { /* No prom memory to free */ @@ -122,10 +84,6 @@ void __init prom_init(void) bd_t *bd = gd->bd; int memsize; -#ifdef CONFIG_SERIAL_ADM8668_CONSOLE - register_console(&early_console); -#endif - memsize = bd->bi_memsize; printk("Board info:\n"); printk(" RAM size: %d MB\n", (int)memsize/(1024*1024)); diff --git a/target/linux/adm8668/files/arch/mips/adm8668/serial.c b/target/linux/adm8668/files/arch/mips/adm8668/serial.c deleted file mode 100644 index 7d684b810..000000000 --- a/target/linux/adm8668/files/arch/mips/adm8668/serial.c +++ /dev/null @@ -1,638 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * ADM8668 serial driver, totally ripped the source from BCM63xx and changed - * all the registers to fit our hardware, and removed all the features that - * I didn't know because our GPL'd serial driver was way lame. - * - * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> - * Derived directly from bcm63xx_uart - * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> - * - */ - -#if defined(CONFIG_SERIAL_ADM8668_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/console.h> -#include <linux/clk.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/sysrq.h> -#include <linux/serial.h> -#include <linux/serial_core.h> -#include <adm8668.h> - -#define ADM8668_NR_UARTS 1 - -static struct uart_port ports[ADM8668_NR_UARTS]; - -/* - * handy uart register accessor - */ -static inline unsigned int adm_uart_readl(struct uart_port *port, - unsigned int offset) -{ - return (*(volatile unsigned int *)(port->membase + offset)); -} - -static inline void adm_uart_writel(struct uart_port *port, - unsigned int value, unsigned int offset) -{ - (*((volatile unsigned int *)(port->membase + offset))) = value; -} - -/* - * serial core request to check if uart tx fifo is empty - */ -static unsigned int adm_uart_tx_empty(struct uart_port *port) -{ - /* we always wait for completion, no buffer is made... */ - return 1; -} - -/* - * serial core request to set RTS and DTR pin state and loopback mode - */ -static void adm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ -} - -/* - * serial core request to return RI, CTS, DCD and DSR pin state - */ -static unsigned int adm_uart_get_mctrl(struct uart_port *port) -{ - return 0; -} - -/* - * serial core request to disable tx ASAP (used for flow control) - */ -static void adm_uart_stop_tx(struct uart_port *port) -{ - unsigned int val; - - val = adm_uart_readl(port, UART_CR_REG); - val &= ~(UART_TX_INT_EN); - adm_uart_writel(port, val, UART_CR_REG); -} - -/* - * serial core request to (re)enable tx - */ -static void adm_uart_start_tx(struct uart_port *port) -{ - unsigned int val; - - val = adm_uart_readl(port, UART_CR_REG); - val |= UART_TX_INT_EN; - adm_uart_writel(port, val, UART_CR_REG); -} - -/* - * serial core request to stop rx, called before port shutdown - */ -static void adm_uart_stop_rx(struct uart_port *port) -{ - unsigned int val; - - val = adm_uart_readl(port, UART_CR_REG); - val &= ~UART_RX_INT_EN; - adm_uart_writel(port, val, UART_CR_REG); -} - -/* - * serial core request to enable modem status interrupt reporting - */ -static void adm_uart_enable_ms(struct uart_port *port) -{ -} - -/* - * serial core request to start/stop emitting break char - */ -static void adm_uart_break_ctl(struct uart_port *port, int ctl) -{ -} - -/* - * return port type in string format - */ -static const char *adm_uart_type(struct uart_port *port) -{ - return (port->type == PORT_ADM8668) ? "adm8668_uart" : NULL; -} - -/* - * read all chars in rx fifo and send them to core - */ -static void adm_uart_do_rx(struct uart_port *port) -{ - struct tty_struct *tty; - unsigned int max_count; - - /* limit number of char read in interrupt, should not be - * higher than fifo size anyway since we're much faster than - * serial port */ - max_count = 32; - tty = port->state->port.tty; - do { - unsigned int iestat, c, cstat; - char flag; - - /* get overrun/fifo empty information from ier - * register */ - iestat = adm_uart_readl(port, UART_FR_REG); - if (iestat & UART_RX_FIFO_EMPTY) - break; - - /* recieve status */ - cstat = adm_uart_readl(port, UART_RSR_REG); - /* clear errors */ - adm_uart_writel(port, cstat, UART_RSR_REG); - - c = adm_uart_readl(port, UART_DR_REG); - port->icount.rx++; - flag = TTY_NORMAL; - - if (unlikely((cstat & UART_RX_STATUS_MASK))) { - /* do stats first */ - if (cstat & UART_BREAK_ERR) { - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } - - if (cstat & UART_PARITY_ERR) - port->icount.parity++; - if (cstat & UART_FRAMING_ERR) - port->icount.frame++; - if (cstat & UART_OVERRUN_ERR) { - port->icount.overrun++; - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - - /* update flag wrt read_status_mask */ - cstat &= port->read_status_mask; - if (cstat & UART_BREAK_ERR) - flag = TTY_BREAK; - if (cstat & UART_FRAMING_ERR) - flag = TTY_FRAME; - if (cstat & UART_PARITY_ERR) - flag = TTY_PARITY; - } - - if (uart_handle_sysrq_char(port, c)) - continue; - - /* fixthis */ - if ((cstat & port->ignore_status_mask) == 0) - tty_insert_flip_char(tty, c, flag); - } while (max_count--); - - tty_flip_buffer_push(tty); -} - -/* - * fill tx fifo with chars to send, stop when fifo is about to be full - * or when all chars have been sent. - */ -static void adm_uart_do_tx(struct uart_port *port) -{ - struct circ_buf *xmit; - - if (port->x_char) { - adm_uart_writel(port, port->x_char, UART_DR_REG); - port->icount.tx++; - port->x_char = 0; - return; - } - - if (uart_tx_stopped(port)) - adm_uart_stop_tx(port); - - xmit = &port->state->xmit; - - if (uart_circ_empty(xmit)) - goto txq_empty; - do - { - while ((adm_uart_readl(port, UART_FR_REG) & UART_TX_FIFO_FULL) != 0) - ; - adm_uart_writel(port, xmit->buf[xmit->tail], UART_DR_REG); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - } while (1); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) - goto txq_empty; - - return; - -txq_empty: - adm_uart_stop_tx(port); -} - -/* - * process uart interrupt - */ -static irqreturn_t adm_uart_interrupt(int irq, void *dev_id) -{ - struct uart_port *port; - unsigned int irqstat; - - port = dev_id; - spin_lock(&port->lock); - - irqstat = adm_uart_readl(port, UART_IIR_REG); - - if (irqstat & (UART_RX_INT|UART_RX_TIMEOUT_INT)) { - adm_uart_do_rx(port); - } - - if (irqstat & UART_TX_INT) { - adm_uart_do_tx(port); - } - spin_unlock(&port->lock); - return IRQ_HANDLED; -} - -/* - * enable rx & tx operation on uart - */ -static void adm_uart_enable(struct uart_port *port) -{ - unsigned int val; - - val = adm_uart_readl(port, UART_CR_REG); - // BREAK_INT too - val |= (UART_RX_INT_EN | UART_RX_TIMEOUT_INT_EN); - adm_uart_writel(port, val, UART_CR_REG); -} - -/* - * disable rx & tx operation on uart - */ -static void adm_uart_disable(struct uart_port *port) -{ - unsigned int val; - - val = adm_uart_readl(port, UART_CR_REG); - val &= ~(UART_TX_INT_EN | UART_RX_INT_EN | UART_RX_TIMEOUT_INT_EN); - adm_uart_writel(port, val, UART_CR_REG); -} - -/* - * clear all unread data in rx fifo and unsent data in tx fifo - */ -static void adm_uart_flush(struct uart_port *port) -{ - /* read any pending char to make sure all irq status are - * cleared */ - (void)adm_uart_readl(port, UART_DR_REG); -} - -/* - * serial core request to initialize uart and start rx operation - */ -static int adm_uart_startup(struct uart_port *port) -{ - int ret; - - /* clear any pending external input interrupt */ - (void)adm_uart_readl(port, UART_IIR_REG); - - /* register irq and enable rx interrupts */ - ret = request_irq(port->irq, adm_uart_interrupt, 0, - adm_uart_type(port), port); - if (ret) - return ret; - - adm_uart_enable(port); - - return 0; -} - -/* - * serial core request to flush & disable uart - */ -static void adm_uart_shutdown(struct uart_port *port) -{ - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); -// adm_uart_writel(port, 0, UART_CR_REG); - spin_unlock_irqrestore(&port->lock, flags); - - adm_uart_disable(port); - adm_uart_flush(port); - free_irq(port->irq, port); -} - -/* - * serial core request to change current uart setting - */ -static void adm_uart_set_termios(struct uart_port *port, - struct ktermios *new, - struct ktermios *old) -{ - port->ignore_status_mask = 0; - uart_update_timeout(port, new->c_cflag, 115200); -} - -/* - * serial core request to claim uart iomem - */ -static int adm_uart_request_port(struct uart_port *port) -{ - unsigned int size = 0xf; - if (!request_mem_region(port->mapbase, size, "adm8668")) { - dev_err(port->dev, "Memory region busy\n"); - return -EBUSY; - } - - port->membase = ioremap(port->mapbase, size); - if (!port->membase) { - dev_err(port->dev, "Unable to map registers\n"); - release_mem_region(port->mapbase, size); - return -EBUSY; - } - return 0; -} - -/* - * serial core request to release uart iomem - */ -static void adm_uart_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, 0xf); - iounmap(port->membase); -} - -/* - * serial core request to do any port required autoconfiguration - */ -static void adm_uart_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - if (adm_uart_request_port(port)) - return; - port->type = PORT_ADM8668; - } -} - -/* - * serial core request to check that port information in serinfo are - * suitable - */ -static int adm_uart_verify_port(struct uart_port *port, - struct serial_struct *serinfo) -{ - if (port->type != PORT_ADM8668) - return -EINVAL; - if (port->irq != serinfo->irq) - return -EINVAL; - if (port->iotype != serinfo->io_type) - return -EINVAL; - if (port->mapbase != (unsigned long)serinfo->iomem_base) - return -EINVAL; - return 0; -} - -/* serial core callbacks */ -static struct uart_ops adm_uart_ops = { - .tx_empty = adm_uart_tx_empty, - .get_mctrl = adm_uart_get_mctrl, - .set_mctrl = adm_uart_set_mctrl, - .start_tx = adm_uart_start_tx, - .stop_tx = adm_uart_stop_tx, - .stop_rx = adm_uart_stop_rx, - .enable_ms = adm_uart_enable_ms, - .break_ctl = adm_uart_break_ctl, - .startup = adm_uart_startup, - .shutdown = adm_uart_shutdown, - .set_termios = adm_uart_set_termios, - .type = adm_uart_type, - .release_port = adm_uart_release_port, - .request_port = adm_uart_request_port, - .config_port = adm_uart_config_port, - .verify_port = adm_uart_verify_port, -}; - -#ifdef CONFIG_SERIAL_ADM8668_CONSOLE -static inline void wait_for_xmitr(struct uart_port *port) -{ - while ((adm_uart_readl(port, UART_FR_REG) & UART_TX_FIFO_FULL) != 0) - ; -} - -/* - * output given char - */ -static void adm_console_putchar(struct uart_port *port, int ch) -{ - wait_for_xmitr(port); - adm_uart_writel(port, ch, UART_DR_REG); -} - -/* - * console core request to output given string - */ -static void adm_console_write(struct console *co, const char *s, - unsigned int count) -{ - struct uart_port *port; - unsigned long flags; - int locked; - - port = &ports[co->index]; - - local_irq_save(flags); - if (port->sysrq) { - /* adm_uart_interrupt() already took the lock */ - locked = 0; - } else if (oops_in_progress) { - locked = spin_trylock(&port->lock); - } else { - spin_lock(&port->lock); - locked = 1; - } - - /* call helper to deal with \r\n */ - uart_console_write(port, s, count, adm_console_putchar); - - /* and wait for char to be transmitted */ - wait_for_xmitr(port); - - if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); -} - -/* - * console core request to setup given console, find matching uart - * port and setup it. - */ -static int adm_console_setup(struct console *co, char *options) -{ - struct uart_port *port; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (co->index < 0 || co->index >= ADM8668_NR_UARTS) - return -EINVAL; - port = &ports[co->index]; - if (!port->membase) - return -ENODEV; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static struct uart_driver adm_uart_driver; - -static struct console adm8668_console = { - .name = "ttyS", - .write = adm_console_write, - .device = uart_console_device, - .setup = adm_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &adm_uart_driver, -}; - -static int __init adm8668_console_init(void) -{ - register_console(&adm8668_console); - return 0; -} - -console_initcall(adm8668_console_init); - -#define ADM8668_CONSOLE (&adm8668_console) -#else -#define ADM8668_CONSOLE NULL -#endif /* CONFIG_SERIAL_ADM8668_CONSOLE */ - -static struct uart_driver adm_uart_driver = { - .owner = THIS_MODULE, - .driver_name = "adm8668_uart", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = 64, - .nr = 1, - .cons = ADM8668_CONSOLE, -}; - -/* - * platform driver probe/remove callback - */ -static int __devinit adm_uart_probe(struct platform_device *pdev) -{ - struct resource *res_mem, *res_irq; - struct uart_port *port; - int ret; - - if (pdev->id < 0 || pdev->id >= ADM8668_NR_UARTS) - return -EINVAL; - - if (ports[pdev->id].membase) - return -EBUSY; - - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res_mem) - return -ENODEV; - - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res_irq) - return -ENODEV; - - port = &ports[pdev->id]; - memset(port, 0, sizeof(*port)); - port->iotype = UPIO_MEM; - port->mapbase = res_mem->start; - port->irq = res_irq->start; - port->ops = &adm_uart_ops; - port->flags = UPF_BOOT_AUTOCONF; - port->dev = &pdev->dev; - port->fifosize = 8; - port->uartclk = ADM8668_UARTCLK_FREQ; - - ret = uart_add_one_port(&adm_uart_driver, port); - if (ret) { - ports[pdev->id].membase = 0; - return ret; - } - platform_set_drvdata(pdev, port); - return 0; -} - -static int __devexit adm_uart_remove(struct platform_device *pdev) -{ - struct uart_port *port; - - port = platform_get_drvdata(pdev); - uart_remove_one_port(&adm_uart_driver, port); - platform_set_drvdata(pdev, NULL); - /* mark port as free */ - ports[pdev->id].membase = 0; - return 0; -} - -/* - * platform driver stuff - */ -static struct platform_driver adm_uart_platform_driver = { - .probe = adm_uart_probe, - .remove = __devexit_p(adm_uart_remove), - .driver = { - .owner = THIS_MODULE, - .name = "adm8668_uart", - }, -}; - -static int __init adm_uart_init(void) -{ - int ret; - - ret = uart_register_driver(&adm_uart_driver); - if (ret) - return ret; - - ret = platform_driver_register(&adm_uart_platform_driver); - if (ret) - uart_unregister_driver(&adm_uart_driver); - - return ret; -} - -static void __exit adm_uart_exit(void) -{ - platform_driver_unregister(&adm_uart_platform_driver); - uart_unregister_driver(&adm_uart_driver); -} - -module_init(adm_uart_init); -module_exit(adm_uart_exit); - -MODULE_AUTHOR("Scott Nicholas <neutronscott@scottn.us>"); -MODULE_DESCRIPTION("ADM8668 integrated uart driver"); -MODULE_LICENSE("GPL"); diff --git a/target/linux/adm8668/files/arch/mips/adm8668/setup.c b/target/linux/adm8668/files/arch/mips/adm8668/setup.c new file mode 100644 index 000000000..b33c483d2 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/setup.c @@ -0,0 +1,36 @@ +#include <linux/init.h> +#include <linux/reboot.h> + +#include <asm/reboot.h> +#include <adm8668.h> + +static void adm8668_restart(char *cmd) +{ + int i; + + /* the real deal */ + for (i = 0; i < 1000; i++) + ; + ADM8668_CONFIG_REG(ADM8668_CR1) = 1; +} + +void __init plat_mem_setup(void) +{ + _machine_restart = adm8668_restart; +} + +const char *get_system_type(void) +{ + unsigned long chipid = ADM8668_CONFIG_REG(ADM8668_CR0); + int product, revision; + static char ret[32]; + + product = chipid >> 16; + revision = chipid & 0xffff; + + /* i getting fancy :\ */ + snprintf(ret, sizeof(ret), "ADM%xr%x", product, revision); + + return ret; +} + diff --git a/target/linux/adm8668/files/arch/mips/adm8668/time.c b/target/linux/adm8668/files/arch/mips/adm8668/time.c new file mode 100644 index 000000000..87bdd6696 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/adm8668/time.c @@ -0,0 +1,20 @@ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/clk.h> + +#include <asm/time.h> +#include <adm8668.h> + +void __init plat_time_init(void) +{ + struct clk *sys_clk; + + adm8668_init_clocks(); + + sys_clk = clk_get(NULL, "sys"); + if (IS_ERR(sys_clk)) + panic("unable to get system clock\n"); + + mips_hpt_frequency = clk_get_rate(sys_clk) / 2; +} + diff --git a/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/adm8668.h b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/adm8668.h index 2cf65d81a..8a16863c0 100644 --- a/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/adm8668.h +++ b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/adm8668.h @@ -9,8 +9,6 @@ #ifndef __ADM8668_H__ #define __ADM8668_H__ -#define SYS_CLOCK 175000000 - /*======================= Physical Memory Map ============================*/ #define ADM8668_SDRAM_BASE 0 #define ADM8668_SMEM1_BASE 0x10000000 @@ -26,71 +24,28 @@ #define ADM8668_SMEM0_BASE 0x1FC00000 #define ADM8668_NAND_BASE 0x1FFFFF00 -#define PCICFG_BASE 0x12200000 -#define PCIDAT_BASE 0x12400000 - -/** onboard uart **/ -#define ADM8668_UARTCLK_FREQ 62500000 -/* registers */ -#define UART_DR_REG 0x00 -#define UART_RSR_REG 0x04 -#define UART_CR_REG 0x14 -#define UART_FR_REG 0x18 -#define UART_IIR_REG 0x1C - -/* rsr reg */ -#define UART_FRAMING_ERR 0x01 -#define UART_PARITY_ERR 0x02 -#define UART_BREAK_ERR 0x04 -#define UART_OVERRUN_ERR 0x08 -#define UART_RX_STATUS_MASK 0x0F - -/* cr reg */ -#define UART_RX_INT_EN 0x10 -#define UART_TX_INT_EN 0x20 -#define UART_RX_TIMEOUT_INT_EN 0x40 - -/* fr reg */ -#define UART_RX_FIFO_EMPTY 0x10 -#define UART_TX_FIFO_FULL 0x20 - -/* iir reg */ -#define UART_RX_INT 0x02 -#define UART_TX_INT 0x04 -#define UART_RX_TIMEOUT_INT 0x08 - -/* interrupt controller */ -#define IRQ_STATUS_REG 0x00 /* Read */ -#define IRQ_ENABLE_REG 0x08 /* Read/Write */ -#define IRQ_DISABLE_REG 0x0C /* Write */ +#define ADM8668_PCICFG_BASE 0x12200000 +#define ADM8668_PCIDAT_BASE 0x12400000 /* interrupt levels */ -#define INT_LVL_SWI 1 -#define INT_LVL_COMMS_RX 2 -#define INT_LVL_COMMS_TX 3 -#define INT_LVL_TIMERINT0 4 -#define INT_LVL_TIMERINT1 5 -#define INT_LVL_UART0 6 -#define INT_LVL_LAN 7 -#define INT_LVL_WAN 8 -#define INT_LVL_WLAN 9 -#define INT_LVL_GPIO 10 -#define INT_LVL_IDE 11 -#define INT_LVL_PCI2 12 -#define INT_LVL_PCI1 13 -#define INT_LVL_PCI0 14 -#define INT_LVL_USB 15 -#define INT_LVL_MAX INT_LVL_USB +#define ADM8668_SWI_IRQ 1 +#define ADM8668_COMMS_RX_IRQ 2 +#define ADM8668_COMMS_TX_IRQ 3 +#define ADM8668_TIMER0_IRQ 4 +#define ADM8668_TIMER1_IRQ 5 +#define ADM8668_UART0_IRQ 6 +#define ADM8668_LAN_IRQ 7 +#define ADM8668_WAN_IRQ 8 +#define ADM8668_WLAN_IRQ 9 +#define ADM8668_GPIO_IRQ 10 +#define ADM8668_IDE_IRQ 11 +#define ADM8668_PCI2_IRQ 12 +#define ADM8668_PCI1_IRQ 13 +#define ADM8668_PCI0_IRQ 14 +#define ADM8668_USB_IRQ 15 +#define ADM8668_IRQ_MAX ADM8668_USB_IRQ /* register access macros */ -#define ADM8668_INTC_REG(_reg) \ - (*((volatile unsigned long *)(KSEG1ADDR(ADM8668_INTC_BASE + (_reg))))) -#define ADM8668_LAN_REG(_reg) \ - (*((volatile unsigned int *)(KSEG1ADDR(ADM8668_LAN_BASE + (_reg))))) -#define ADM8668_WAN_REG(_reg) \ - (*((volatile unsigned int *)(KSEG1ADDR(ADM8668_WAN_BASE + (_reg))))) -#define ADM8668_WLAN_REG(_reg) \ - (*((volatile unsigned int *)(KSEG1ADDR(ADM8668_WLAN_BASE + (_reg))))) #define ADM8668_CONFIG_REG(_reg) \ (*((volatile unsigned int *)(KSEG1ADDR(ADM8668_CONFIG_BASE + (_reg))))) @@ -103,37 +58,12 @@ #define ADM8668_CR0 0x00 #define ADM8668_CR1 0x04 #define ADM8668_CR3 0x0C +#define ADM8668_CR66 0x108 /** For GPIO control **/ #define GPIO_REG 0x5C /* on WLAN */ #define CRGPIO_REG 0x20 /* on CPU */ -#define GPIO0_OUTPUT_ENABLE 0x1000 -#define GPIO1_OUTPUT_ENABLE 0x2000 -#define GPIO2_OUTPUT_ENABLE 0x4000 -#define GPIO_OUTPUT_ENABLE_ALL 0x7000 -#define GPIO0_OUTPUT_1 0x40 -#define GPIO1_OUTPUT_1 0x80 -#define GPIO2_OUTPUT_1 0x100 -#define GPIO0_INPUT_1 0x1 -#define GPIO1_INPUT_1 0x2 -#define GPIO2_INPUT_1 0x4 - -#define GPIO_SET_HI(num) \ - ADM8668_WLAN_REG(GPIO_REG) |= (1 << (6 + num)) - -#define GPIO_SET_LOW(num) \ - ADM8668_WLAN_REG(GPIO_REG) &= ~(1 << (6 + num)) - -#define GPIO_TOGGLE(num) \ - ADM8668_WLAN_REG(GPIO_REG) ^= (1 << (6 + num)) - -#define CRGPIO_SET_HI(num) \ - ADM8668_CONFIG_REG(CRGPIO_REG) |= (1 << (6 + num)) - -#define CRGPIO_SET_LOW(num) \ - ADM8668_CONFIG_REG(CRGPIO_REG) &= ~(1 << (6 + num)) -#define CRGPIO_TOGGLE(num) \ - ADM8668_CONFIG_REG(CRGPIO_REG) ^= (1 << (6 + num)) +void adm8668_init_clocks(void); #endif /* __ADM8668_H__ */ diff --git a/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/asm/sizes.h b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/asm/sizes.h new file mode 100644 index 000000000..503843db1 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/asm/sizes.h @@ -0,0 +1,56 @@ +/* + * 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 + */ +/* DO NOT EDIT!! - this file automatically generated + * from .s file by awk -f s2h.awk + */ +/* Size definitions + * Copyright (C) ARM Limited 1998. All rights reserved. + */ + +#ifndef __sizes_h +#define __sizes_h 1 + +/* handy sizes */ +#define SZ_16 0x00000010 +#define SZ_256 0x00000100 +#define SZ_512 0x00000200 + +#define SZ_1K 0x00000400 +#define SZ_4K 0x00001000 +#define SZ_8K 0x00002000 +#define SZ_16K 0x00004000 +#define SZ_64K 0x00010000 +#define SZ_128K 0x00020000 +#define SZ_256K 0x00040000 +#define SZ_512K 0x00080000 + +#define SZ_1M 0x00100000 +#define SZ_2M 0x00200000 +#define SZ_4M 0x00400000 +#define SZ_8M 0x00800000 +#define SZ_16M 0x01000000 +#define SZ_32M 0x02000000 +#define SZ_64M 0x04000000 +#define SZ_128M 0x08000000 +#define SZ_256M 0x10000000 +#define SZ_512M 0x20000000 + +#define SZ_1G 0x40000000 +#define SZ_2G 0x80000000 + +#endif + +/* END */ diff --git a/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/gpio.h b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/gpio.h new file mode 100644 index 000000000..b0473fc4b --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/gpio.h @@ -0,0 +1,13 @@ +#ifndef __ADM8668_GPIO_H__ +#define __ADM8668_GPIO_H__ + +#define gpio_to_irq(gpio) -1 + +#define gpio_get_value __gpio_get_value +#define gpio_set_value __gpio_set_value + +#define gpio_cansleep __gpio_cansleep + +#include <asm-generic/gpio.h> + +#endif diff --git a/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/irq.h b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/irq.h index 1341309f2..ea859f03a 100644 --- a/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/irq.h +++ b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/irq.h @@ -8,9 +8,7 @@ #ifndef __ASM_MACH_ADM8668_IRQ_H #define __ASM_MACH_ADM8668_IRQ_H -#define NR_IRQS 32 +#define NR_IRQS 32 #define MIPS_CPU_IRQ_BASE 16 -#define IRQ_MASK 0xffff - #endif /* __ASM_MACH_ADM8668_IRQ_H */ diff --git a/target/linux/adm8668/files/arch/mips/pci/pci-adm8668.c b/target/linux/adm8668/files/arch/mips/pci/pci-adm8668.c new file mode 100644 index 000000000..5cfa54604 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/pci/pci-adm8668.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> + * Copyright (C) 2012 Florian Fainelli <florian@openwrt.org> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Note that this controller is identical to the ADM5120 one + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/types.h> +#include <linux/spinlock.h> + +#include <asm/byteorder.h> +#include <asm/pci.h> +#include <adm8668.h> + +static DEFINE_SPINLOCK(pci_lock); + +#define PCI_ENABLE 0x80000000 +#define ADMPCI_IO_BASE 0x12600000 +#define ADMPCI_IO_SIZE 0x1fffff +#define ADMPCI_MEM_BASE 0x16000000 +#define ADMPCI_MEM_SIZE 0x7ffffff + +static inline void write_cfgaddr(u32 addr) +{ + __raw_writel((addr | PCI_ENABLE), + (void __iomem *)KSEG1ADDR(ADM8668_PCICFG_BASE)); +} + +static inline void write_cfgdata(u32 data) +{ + __raw_writel(data, (void __iomem *)KSEG1ADDR(ADM8668_PCIDAT_BASE)); +} + +static inline u32 read_cfgdata(void) +{ + return __raw_readl((void __iomem *)KSEG1ADDR(ADM8668_PCIDAT_BASE)); +} + +static inline u32 mkaddr(struct pci_bus *bus, unsigned int devfn, int where) +{ + return ((bus->number & 0xff) << 16) | ((devfn & 0xff) << 8) | + (where & 0xfc); +} + +static int pci_read_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + unsigned long flags; + u32 data; + + spin_lock_irqsave(&pci_lock, flags); + write_cfgaddr(mkaddr(bus, devfn, where)); + data = read_cfgdata(); + + switch (size) { + case 1: + if (where & 1) + data >>= 8; + if (where & 2) + data >>= 16; + data &= 0xff; + break; + case 2: + if (where & 2) + data >>= 16; + data &= 0xffff; + break; + } + + *val = data; + + spin_unlock_irqrestore(&pci_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +static int pci_write_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + unsigned long flags; + u32 data; + int s; + + spin_lock_irqsave(&pci_lock, flags); + + write_cfgaddr(mkaddr(bus, devfn, where)); + data = read_cfgdata(); + + switch (size) { + case 1: + s = ((where & 3) << 3); + data &= ~(0xff << s); + data |= ((val & 0xff) << s); + break; + case 2: + s = ((where & 2) << 4); + data &= ~(0xffff << s); + data |= ((val & 0xffff) << s); + break; + case 4: + data = val; + break; + } + + write_cfgdata(data); + + spin_unlock_irqrestore(&pci_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops adm8668_pci_ops = { + .read = pci_read_config, + .write = pci_write_config +}; + + +struct resource pciioport_resource = { + .name = "adm8668_pci", + .start = ADMPCI_IO_BASE, + .end = ADMPCI_IO_BASE + ADMPCI_IO_SIZE, + .flags = IORESOURCE_IO +}; + +struct resource pciiomem_resource = { + .name = "adm8668_pci", + .start = ADMPCI_MEM_BASE, + .end = ADMPCI_MEM_BASE + ADMPCI_MEM_SIZE, + .flags = IORESOURCE_MEM +}; + +struct pci_controller adm8668_pci_controller = { + .pci_ops = &adm8668_pci_ops, + .io_resource = &pciioport_resource, + .mem_resource = &pciiomem_resource, +}; + +int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + switch (slot) { + case 1: + return 14; + case 2: + return 13; + case 3: + return 12; + default: + return dev->irq; + } +} + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} + +static void adm8668_pci_fixup(struct pci_dev *dev) +{ + if (dev->devfn != 0) + return; + + pr_info("PCI: fixing up ADM8668 controller\n"); + + /* setup COMMAND register */ + pci_write_config_word(dev, PCI_COMMAND, + (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER)); + + /* setup CACHE_LINE_SIZE register */ + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 4); + + /* setup BARS */ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0); +} +DECLARE_PCI_FIXUP_HEADER(0x1317, 0x8688, adm8668_pci_fixup); + +static int __init adm8668_pci_init(void) +{ + void __iomem *io_map_base; + + ioport_resource.start = ADMPCI_IO_BASE; + ioport_resource.end = ADMPCI_IO_BASE + ADMPCI_IO_SIZE; + + io_map_base = ioremap(ADMPCI_IO_BASE, ADMPCI_IO_SIZE); + if (!io_map_base) + printk("io_map_base didn't work.\n"); + + adm8668_pci_controller.io_map_base = (unsigned long)io_map_base; + register_pci_controller(&adm8668_pci_controller); + + return 0; +} +arch_initcall(adm8668_pci_init); diff --git a/target/linux/adm8668/files/drivers/mtd/maps/adm8668.c b/target/linux/adm8668/files/drivers/mtd/maps/adm8668.c index e360a0d78..7ef0adac4 100644 --- a/target/linux/adm8668/files/drivers/mtd/maps/adm8668.c +++ b/target/linux/adm8668/files/drivers/mtd/maps/adm8668.c @@ -1,30 +1,30 @@ /* - * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> - * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org> - * Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org> - * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org) + * Infineon/ADMTek ADM8668 (WildPass) partition parser support * - * original functions for finding root filesystem from Mike Baker + * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> + * Copyright (C) 2012 Florian Fainelli <florian@openwrt.org> * - * 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. + * original functions for finding root filesystem from Mike Baker * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. * * * Copyright 2004, Broadcom Corporation @@ -34,9 +34,6 @@ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. - * - * Flash mapping for adm8668 boards - * */ #include <linux/module.h> @@ -45,16 +42,13 @@ #include <linux/sched.h> #include <linux/wait.h> #include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/slab.h> #include <linux/mtd/partitions.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> #include <linux/crc32.h> #include <linux/magic.h> -#include <asm/io.h> -#define WINDOW_ADDR 0x10000000 -#define WINDOW_SIZE 0x800000 -#define BANKWIDTH 2 +#define PFX "adm8668-part: " /* first a little bit about the headers i need.. */ @@ -81,176 +75,122 @@ struct uboot_header { char ih_name[32]; /* image name */ }; -/************************************************/ - -static struct mtd_info *adm8668_mtd; - -struct map_info adm8668_map = { - name: "adm8668-nor", - size: WINDOW_SIZE, - phys: WINDOW_ADDR, - bankwidth: BANKWIDTH, -}; - -/* - * Copied from mtdblock.c - * - * Cache stuff... - * - * Since typical flash erasable sectors are much larger than what Linux's - * buffer cache can handle, we must implement read-modify-write on flash - * sectors for each block write requests. To avoid over-erasing flash sectors - * and to speed things up, we locally cache a whole flash sector while it is - * being written to until a different sector is required. - */ - -static void erase_callback(struct erase_info *done) -{ - wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; - wake_up(wait_q); -} - -static int erase_write (struct mtd_info *mtd, unsigned long pos, - int len, const char *buf) -{ - struct erase_info erase; - DECLARE_WAITQUEUE(wait, current); - wait_queue_head_t wait_q; - size_t retlen; - int ret; - - /* - * First, let's erase the flash block. - */ - - init_waitqueue_head(&wait_q); - erase.mtd = mtd; - erase.callback = erase_callback; - erase.addr = pos; - erase.len = len; - erase.priv = (u_long)&wait_q; - - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&wait_q, &wait); - - ret = mtd->erase(mtd, &erase); - if (ret) { - set_current_state(TASK_RUNNING); - remove_wait_queue(&wait_q, &wait); - printk (KERN_WARNING "erase of region [0x%lx, 0x%x] " - "on \"%s\" failed\n", - pos, len, mtd->name); - return ret; - } - - schedule(); /* Wait for erase to finish. */ - remove_wait_queue(&wait_q, &wait); - - /* - * Next, write data to flash. - */ - - ret = mtd->write (mtd, pos, len, &retlen, buf); - if (ret) - return ret; - if (retlen != len) - return -EIO; - return 0; -} - -/* decent defaults in case... shrug */ -static struct mtd_partition adm8668_parts[] = { - { name: "linux", offset: 0x40000, size: WINDOW_SIZE-0x40000, }, - { name: "rootfs", offset: 0xe0000, size: 0x140000, }, - { name: "uboot_env", offset: 0x20000, size: 0x20000, }, - { name: NULL, }, -}; - /* in case i wanna change stuff later, and to clarify the math section... */ #define PART_LINUX 0 #define PART_ROOTFS 1 +#define PART_UBOOT_ENV 2 #define NR_PARTS 3 -static int __init -init_mtd_partitions(struct mtd_info *mtd, size_t size) +static int adm8668_parse_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { + int ret; struct uboot_header uhdr; int off, blocksize; size_t len, linux_len; struct squashfs_super_block shdr; + struct erase_info erase_info; + struct mtd_partition *adm8668_parts; + + memset(&erase_info, 0, sizeof(erase_info)); + + blocksize = master->erasesize; - blocksize = mtd->erasesize; if (blocksize < 0x10000) blocksize = 0x10000; + adm8668_parts = kzalloc(sizeof(*adm8668_parts) * NR_PARTS, GFP_KERNEL); + if (!adm8668_parts) + return -ENOMEM; + + adm8668_parts[PART_LINUX].name = kstrdup("linux", GFP_KERNEL); + adm8668_parts[PART_LINUX].offset = 0x40000; + adm8668_parts[PART_LINUX].size = master->size - 0x40000; + adm8668_parts[PART_ROOTFS].name = kstrdup("rootfs", GFP_KERNEL); + adm8668_parts[PART_ROOTFS].offset = 0xe0000; + adm8668_parts[PART_ROOTFS].size = 0x140000; + adm8668_parts[PART_UBOOT_ENV].name = kstrdup("uboot_env", GFP_KERNEL); + adm8668_parts[PART_UBOOT_ENV].offset = 0x20000; + adm8668_parts[PART_UBOOT_ENV].size = 0x20000; + /* now find squashfs */ memset(&shdr, 0xe5, sizeof(shdr)); - for (off = adm8668_parts[PART_LINUX].offset; off < size; off += blocksize) { + + for (off = 0x40000; off < master->size; off += blocksize) { /* * Read into buffer */ - if (mtd->read(mtd, off, sizeof(shdr), &len, (char *)&shdr) || + if (mtd_read(master, off, sizeof(shdr), &len, (char *)&shdr) || len != sizeof(shdr)) continue; if (shdr.s_magic == SQUASHFS_MAGIC) { uint32_t fs_size = (uint32_t)shdr.bytes_used; - printk(KERN_INFO "%s: Filesystem type: squashfs, size=%dkB\n", - mtd->name, fs_size>>10); + pr_info(PFX "filesystem type: squashfs, size=%dkB\n", + fs_size >> 10); - /* Update rootfs based on the superblock info, and - * stretch to end of MTD. rootfs_split will split it */ + /* + * Update rootfs based on the superblock info, and + * stretch to end of MTD. rootfs_split will split it + */ adm8668_parts[PART_ROOTFS].offset = off; - adm8668_parts[PART_ROOTFS].size = mtd->size - + adm8668_parts[PART_ROOTFS].size = master->size - adm8668_parts[PART_ROOTFS].offset; - /* kernel ends where rootfs starts - * but we'll keep it full-length for upgrades */ - linux_len = adm8668_parts[PART_LINUX+1].offset - + /* + * kernel ends where rootfs starts + * but we'll keep it full-length for upgrades + */ + linux_len = adm8668_parts[PART_LINUX + 1].offset - adm8668_parts[PART_LINUX].offset; -#if 1 - adm8668_parts[PART_LINUX].size = mtd->size - + + adm8668_parts[PART_LINUX].size = master->size - adm8668_parts[PART_LINUX].offset; -#else - adm8668_parts[PART_LINUX].size = linux_len; -#endif goto found; } } - printk(KERN_NOTICE - "%s: Couldn't find root filesystem\n", - mtd->name); + pr_err(PFX "could't find root filesystem\n"); return NR_PARTS; - found: - if (mtd->read(mtd, adm8668_parts[PART_LINUX].offset, sizeof(uhdr), &len, (char *)&uhdr) || - len != sizeof(uhdr)) +found: + if (mtd_read(master, adm8668_parts[PART_LINUX].offset, sizeof(uhdr), &len, (char *)&uhdr) || + len != sizeof(uhdr)) { + pr_err(PFX "failed to read u-boot header\n"); return NR_PARTS; + } - /* that's odd. how'd ya boot it then */ - if (uhdr.ih_magic != IH_MAGIC) + if (uhdr.ih_magic != IH_MAGIC) { + pr_info(PFX "invalid u-boot magic detected?!?!\n"); return NR_PARTS; + } if (be32_to_cpu(uhdr.ih_size) != (linux_len - sizeof(uhdr))) { - unsigned char *block, *data; + u32 data; + size_t data_len = 0; + unsigned char *block; unsigned int offset; offset = adm8668_parts[PART_LINUX].offset + sizeof(struct uboot_header); - data = (unsigned char *)(WINDOW_ADDR | 0xA0000000 | offset); - printk(KERN_NOTICE "Updating U-boot image:\n"); - printk(KERN_NOTICE " old: [size: %8d crc32: 0x%08x]\n", + pr_info(PFX "Updating U-boot image:\n"); + pr_info(PFX " old: [size: %8d crc32: 0x%08x]\n", be32_to_cpu(uhdr.ih_size), be32_to_cpu(uhdr.ih_dcrc)); + if (mtd_read(master, offset, sizeof(data), &data_len, (char *)&data)) { + pr_err(PFX "failed to read data\n"); + goto out; + } + /* Update the data length & crc32 */ uhdr.ih_size = cpu_to_be32(linux_len - sizeof(uhdr)); - uhdr.ih_dcrc = crc32_le(~0, data, linux_len - sizeof(uhdr)) ^ (~0); + uhdr.ih_dcrc = crc32_le(~0, (char *)&data, linux_len - sizeof(uhdr)) ^ (~0); uhdr.ih_dcrc = cpu_to_be32(uhdr.ih_dcrc); - printk(KERN_NOTICE " new: [size: %8d crc32: 0x%08x]\n", + pr_info(PFX " new: [size: %8d crc32: 0x%08x]\n", be32_to_cpu(uhdr.ih_size), be32_to_cpu(uhdr.ih_dcrc)); /* update header's crc... */ @@ -260,75 +200,64 @@ init_mtd_partitions(struct mtd_info *mtd, size_t size) uhdr.ih_hcrc = cpu_to_be32(uhdr.ih_hcrc); /* read first eraseblock from the image */ - block = kmalloc(mtd->erasesize, GFP_KERNEL); - if (mtd->read(mtd, adm8668_parts[PART_LINUX].offset, mtd->erasesize, &len, block) || len != mtd->erasesize) { - printk("Error copying first eraseblock\n"); + block = vmalloc(master->erasesize); + if (!block) + return -ENOMEM; + + if (mtd_read(master, adm8668_parts[PART_LINUX].offset, master->erasesize, &len, block) + || len != master->erasesize) { + pr_err(PFX "error copying first eraseblock\n"); return 0; } /* Write updated header to the flash */ memcpy(block, &uhdr, sizeof(uhdr)); - if (mtd->unlock) - mtd->unlock(mtd, off, mtd->erasesize); - erase_write(mtd, adm8668_parts[PART_LINUX].offset, mtd->erasesize, block); - if (mtd->sync) - mtd->sync(mtd); - kfree(block); - printk(KERN_NOTICE "Done\n"); + if (master->unlock) + master->unlock(master, off, master->erasesize); + + erase_info.mtd = master; + erase_info.addr = (uint64_t)adm8668_parts[PART_LINUX].offset; + erase_info.len = master->erasesize; + ret = mtd_erase(master, &erase_info); + if (!ret) { + if (mtd_write(master, adm8668_parts[PART_LINUX].offset, master->erasesize, + &len, block)) + pr_err(PFX "write failed"); + } else + pr_err(PFX "erase failed"); + + mtd_sync(master); +out: + if (block) + vfree(block); + pr_info(PFX "done\n"); } + *pparts = adm8668_parts; + return NR_PARTS; } -int __init init_adm8668_map(void) -{ - int nr_parts, ret; - - adm8668_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); - - if (!adm8668_map.virt) { - printk(KERN_ERR "Failed to ioremap\n"); - return -EIO; - } - - simple_map_init(&adm8668_map); - if (!(adm8668_mtd = do_map_probe("cfi_probe", &adm8668_map))) { - printk(KERN_ERR "cfi_probe failed\n"); - iounmap((void *)adm8668_map.virt); - return -ENXIO; - } - - adm8668_mtd->owner = THIS_MODULE; - - nr_parts = init_mtd_partitions(adm8668_mtd, adm8668_mtd->size); - ret = mtd_device_register(adm8668_mtd, adm8668_parts, nr_parts); - if (ret) { - printk(KERN_ERR "Flash: mtd_device_register failed\n"); - goto fail; - } - - return 0; +static struct mtd_part_parser adm8668_parser = { + .owner = THIS_MODULE, + .parse_fn = adm8668_parse_partitions, + .name = "adm8668part", +}; - fail: - if (adm8668_mtd) - map_destroy(adm8668_mtd); - if (adm8668_map.virt) - iounmap((void *) adm8668_map.virt); - adm8668_map.virt = 0; - return ret; +static int __init adm8668_parser_init(void) +{ + return register_mtd_parser(&adm8668_parser); } -void __exit cleanup_adm8668_map(void) +static void __exit adm8668_parser_exit(void) { - mtd_device_unregister(adm8668_mtd); - map_destroy(adm8668_mtd); - iounmap((void *) adm8668_map.virt); - adm8668_map.virt = 0; + deregister_mtd_parser(&adm8668_parser); } -module_init(init_adm8668_map); -module_exit(cleanup_adm8668_map); +module_init(adm8668_parser_init); +module_exit(adm8668_parser_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Scott Nicholas <neutronscott@scottn.us>"); -MODULE_DESCRIPTION("MTD map driver for ADM8668 NOR Flash"); +MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); +MODULE_DESCRIPTION("MTD partition parser for ADM8668"); |