diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-30 11:45:52 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-30 11:45:52 -0700 |
commit | 287dc4b7642df15fa6b9f286c812e79138acd698 (patch) | |
tree | c3ebe1caea100ff2b8f414619ec0a9dcd8a14547 /drivers | |
parent | 720d85075b7ed3617de8ca8d9097390e303e9f60 (diff) | |
parent | 68d8848567ef03eb2c2303173934428d0bf0a531 (diff) |
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
Pull MIPS updates from Ralf Baechle:
"More hardware support across the field including a bunch of device
drivers. The highlight however really are further steps towards
device tree.
This has been sitting in -next for ages. All MIPS _defconfigs have
been tested to boot or where I don't have hardware available, to at
least build fine."
* 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (77 commits)
MIPS: Loongson 1B: Add defconfig
MIPS: Loongson 1B: Add board support
MIPS: Netlogic: early console fix
MIPS: Netlogic: Fix indentation of smpboot.S
MIPS: Netlogic: remove cpu_has_dc_aliases define for XLP
MIPS: Netlogic: Remove unused pcibios_fixups
MIPS: Netlogic: Add XLP SoC devices in FDT
MIPS: Netlogic: Add IRQ mappings for more devices
MIPS: Netlogic: USB support for XLP
MIPS: Netlogic: XLP PCIe controller support.
MIPS: Netlogic: Platform changes for XLR/XLS I2C
MIPS: Netlogic: Platform NAND/NOR flash support
MIPS: Netlogic: Platform changes for XLS USB
MIPS: Netlogic: Remove NETLOGIC_ prefix
MIPS: Netlogic: SMP wakeup code update
MIPS: Netlogic: Update comments in smpboot.S
MIPS: BCM63XX: Add 96328avng reference board
MIPS: Expose PCIe drivers for MIPS
MIPS: BCM63XX: Add PCIe Support for BCM6328
MIPS: BCM63XX: Move the PCI initialization into its own function
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/hw_random/Kconfig | 14 | ||||
-rw-r--r-- | drivers/char/hw_random/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/hw_random/bcm63xx-rng.c | 175 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-octeon.c | 92 | ||||
-rw-r--r-- | drivers/mtd/nand/jz4740_nand.c | 228 | ||||
-rw-r--r-- | drivers/net/ethernet/octeon/octeon_mgmt.c | 312 | ||||
-rw-r--r-- | drivers/net/phy/mdio-octeon.c | 92 | ||||
-rw-r--r-- | drivers/spi/Kconfig | 9 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/spi-falcon.c | 469 | ||||
-rw-r--r-- | drivers/staging/octeon/ethernet-mdio.c | 28 | ||||
-rw-r--r-- | drivers/staging/octeon/ethernet.c | 153 | ||||
-rw-r--r-- | drivers/staging/octeon/octeon-ethernet.h | 3 |
13 files changed, 1292 insertions, 285 deletions
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index b01d6732824..7c0d391996b 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -73,6 +73,20 @@ config HW_RANDOM_ATMEL If unsure, say Y. +config HW_RANDOM_BCM63XX + tristate "Broadcom BCM63xx Random Number Generator support" + depends on HW_RANDOM && BCM63XX + default HW_RANDOM + ---help--- + This driver provides kernel-side support for the Random Number + Generator hardware found on the Broadcom BCM63xx SoCs. + + To compile this driver as a module, choose M here: the + module will be called bcm63xx-rng + + If unusure, say Y. + + config HW_RANDOM_GEODE tristate "AMD Geode HW Random Number Generator support" depends on HW_RANDOM && X86_32 && PCI diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 8d6d173b65e..39a757ca15b 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o +obj-$(CONFIG_HW_RANDOM_BCM63XX) += bcm63xx-rng.o obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o n2-rng-y := n2-drv.o n2-asm.o diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c new file mode 100644 index 00000000000..aec6a4277ca --- /dev/null +++ b/drivers/char/hw_random/bcm63xx-rng.c @@ -0,0 +1,175 @@ +/* + * Broadcom BCM63xx Random Number Generator support + * + * Copyright (C) 2011, Florian Fainelli <florian@openwrt.org> + * Copyright (C) 2009, Broadcom Corporation + * + */ +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/hw_random.h> + +#include <bcm63xx_io.h> +#include <bcm63xx_regs.h> + +struct bcm63xx_rng_priv { + struct clk *clk; + void __iomem *regs; +}; + +#define to_rng_priv(rng) ((struct bcm63xx_rng_priv *)rng->priv) + +static int bcm63xx_rng_init(struct hwrng *rng) +{ + struct bcm63xx_rng_priv *priv = to_rng_priv(rng); + u32 val; + + val = bcm_readl(priv->regs + RNG_CTRL); + val |= RNG_EN; + bcm_writel(val, priv->regs + RNG_CTRL); + + return 0; +} + +static void bcm63xx_rng_cleanup(struct hwrng *rng) +{ + struct bcm63xx_rng_priv *priv = to_rng_priv(rng); + u32 val; + + val = bcm_readl(priv->regs + RNG_CTRL); + val &= ~RNG_EN; + bcm_writel(val, priv->regs + RNG_CTRL); +} + +static int bcm63xx_rng_data_present(struct hwrng *rng, int wait) +{ + struct bcm63xx_rng_priv *priv = to_rng_priv(rng); + + return bcm_readl(priv->regs + RNG_STAT) & RNG_AVAIL_MASK; +} + +static int bcm63xx_rng_data_read(struct hwrng *rng, u32 *data) +{ + struct bcm63xx_rng_priv *priv = to_rng_priv(rng); + + *data = bcm_readl(priv->regs + RNG_DATA); + + return 4; +} + +static int __devinit bcm63xx_rng_probe(struct platform_device *pdev) +{ + struct resource *r; + struct clk *clk; + int ret; + struct bcm63xx_rng_priv *priv; + struct hwrng *rng; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "no iomem resource\n"); + ret = -ENXIO; + goto out; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "no memory for private structure\n"); + ret = -ENOMEM; + goto out; + } + + rng = kzalloc(sizeof(*rng), GFP_KERNEL); + if (!rng) { + dev_err(&pdev->dev, "no memory for rng structure\n"); + ret = -ENOMEM; + goto out_free_priv; + } + + platform_set_drvdata(pdev, rng); + rng->priv = (unsigned long)priv; + rng->name = pdev->name; + rng->init = bcm63xx_rng_init; + rng->cleanup = bcm63xx_rng_cleanup; + rng->data_present = bcm63xx_rng_data_present; + rng->data_read = bcm63xx_rng_data_read; + + clk = clk_get(&pdev->dev, "ipsec"); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "no clock for device\n"); + ret = PTR_ERR(clk); + goto out_free_rng; + } + + priv->clk = clk; + + if (!devm_request_mem_region(&pdev->dev, r->start, + resource_size(r), pdev->name)) { + dev_err(&pdev->dev, "request mem failed"); + ret = -ENOMEM; + goto out_free_rng; + } + + priv->regs = devm_ioremap_nocache(&pdev->dev, r->start, + resource_size(r)); + if (!priv->regs) { + dev_err(&pdev->dev, "ioremap failed"); + ret = -ENOMEM; + goto out_free_rng; + } + + clk_enable(clk); + + ret = hwrng_register(rng); + if (ret) { + dev_err(&pdev->dev, "failed to register rng device\n"); + goto out_clk_disable; + } + + dev_info(&pdev->dev, "registered RNG driver\n"); + + return 0; + +out_clk_disable: + clk_disable(clk); +out_free_rng: + platform_set_drvdata(pdev, NULL); + kfree(rng); +out_free_priv: + kfree(priv); +out: + return ret; +} + +static int __devexit bcm63xx_rng_remove(struct platform_device *pdev) +{ + struct hwrng *rng = platform_get_drvdata(pdev); + struct bcm63xx_rng_priv *priv = to_rng_priv(rng); + + hwrng_unregister(rng); + clk_disable(priv->clk); + kfree(priv); + kfree(rng); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver bcm63xx_rng_driver = { + .probe = bcm63xx_rng_probe, + .remove = __devexit_p(bcm63xx_rng_remove), + .driver = { + .name = "bcm63xx-rng", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(bcm63xx_rng_driver); + +MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); +MODULE_DESCRIPTION("Broadcom BCM63xx RNG driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon.c index ee139a59881..f44c83549fe 100644 --- a/drivers/i2c/busses/i2c-octeon.c +++ b/drivers/i2c/busses/i2c-octeon.c @@ -2,7 +2,7 @@ * (C) Copyright 2009-2010 * Nokia Siemens Networks, michael.lawnick.ext@nsn.com * - * Portions Copyright (C) 2010 Cavium Networks, Inc. + * Portions Copyright (C) 2010, 2011 Cavium Networks, Inc. * * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors. * @@ -11,17 +11,18 @@ * warranty of any kind, whether express or implied. */ +#include <linux/platform_device.h> +#include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of_i2c.h> +#include <linux/delay.h> #include <linux/sched.h> #include <linux/slab.h> #include <linux/init.h> - -#include <linux/io.h> #include <linux/i2c.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/of.h> #include <asm/octeon/octeon.h> @@ -65,7 +66,7 @@ struct octeon_i2c { wait_queue_head_t queue; struct i2c_adapter adap; int irq; - int twsi_freq; + u32 twsi_freq; int sys_freq; resource_size_t twsi_phys; void __iomem *twsi_base; @@ -121,10 +122,8 @@ static u8 octeon_i2c_read_sw(struct octeon_i2c *i2c, u64 eop_reg) */ static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data) { - u64 tmp; - __raw_writeq(data, i2c->twsi_base + TWSI_INT); - tmp = __raw_readq(i2c->twsi_base + TWSI_INT); + __raw_readq(i2c->twsi_base + TWSI_INT); } /** @@ -515,7 +514,6 @@ static int __devinit octeon_i2c_probe(struct platform_device *pdev) { int irq, result = 0; struct octeon_i2c *i2c; - struct octeon_i2c_data *i2c_data; struct resource *res_mem; /* All adaptors have an irq. */ @@ -523,86 +521,90 @@ static int __devinit octeon_i2c_probe(struct platform_device *pdev) if (irq < 0) return irq; - i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); if (!i2c) { dev_err(&pdev->dev, "kzalloc failed\n"); result = -ENOMEM; goto out; } i2c->dev = &pdev->dev; - i2c_data = pdev->dev.platform_data; res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res_mem == NULL) { dev_err(i2c->dev, "found no memory resource\n"); result = -ENXIO; - goto fail_region; + goto out; } + i2c->twsi_phys = res_mem->start; + i2c->regsize = resource_size(res_mem); - if (i2c_data == NULL) { - dev_err(i2c->dev, "no I2C frequency data\n"); + /* + * "clock-rate" is a legacy binding, the official binding is + * "clock-frequency". Try the official one first and then + * fall back if it doesn't exist. + */ + if (of_property_read_u32(pdev->dev.of_node, + "clock-frequency", &i2c->twsi_freq) && + of_property_read_u32(pdev->dev.of_node, + "clock-rate", &i2c->twsi_freq)) { + dev_err(i2c->dev, + "no I2C 'clock-rate' or 'clock-frequency' property\n"); result = -ENXIO; - goto fail_region; + goto out; } - i2c->twsi_phys = res_mem->start; - i2c->regsize = resource_size(res_mem); - i2c->twsi_freq = i2c_data->i2c_freq; - i2c->sys_freq = i2c_data->sys_freq; + i2c->sys_freq = octeon_get_io_clock_rate(); - if (!request_mem_region(i2c->twsi_phys, i2c->regsize, res_mem->name)) { + if (!devm_request_mem_region(&pdev->dev, i2c->twsi_phys, i2c->regsize, + res_mem->name)) { dev_err(i2c->dev, "request_mem_region failed\n"); - goto fail_region; + goto out; } - i2c->twsi_base = ioremap(i2c->twsi_phys, i2c->regsize); + i2c->twsi_base = devm_ioremap(&pdev->dev, i2c->twsi_phys, i2c->regsize); init_waitqueue_head(&i2c->queue); i2c->irq = irq; - result = request_irq(i2c->irq, octeon_i2c_isr, 0, DRV_NAME, i2c); + result = devm_request_irq(&pdev->dev, i2c->irq, + octeon_i2c_isr, 0, DRV_NAME, i2c); if (result < 0) { dev_err(i2c->dev, "failed to attach interrupt\n"); - goto fail_irq; + goto out; } result = octeon_i2c_initlowlevel(i2c); if (result) { dev_err(i2c->dev, "init low level failed\n"); - goto fail_add; + goto out; } result = octeon_i2c_setclock(i2c); if (result) { dev_err(i2c->dev, "clock init failed\n"); - goto fail_add; + goto out; } i2c->adap = octeon_i2c_ops; i2c->adap.dev.parent = &pdev->dev; - i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0; + i2c->adap.dev.of_node = pdev->dev.of_node; i2c_set_adapdata(&i2c->adap, i2c); platform_set_drvdata(pdev, i2c); - result = i2c_add_numbered_adapter(&i2c->adap); + result = i2c_add_adapter(&i2c->adap); if (result < 0) { dev_err(i2c->dev, "failed to add adapter\n"); goto fail_add; } - dev_info(i2c->dev, "version %s\n", DRV_VERSION); - return result; + of_i2c_register_devices(&i2c->adap); + + return 0; fail_add: platform_set_drvdata(pdev, NULL); - free_irq(i2c->irq, i2c); -fail_irq: - iounmap(i2c->twsi_base); - release_mem_region(i2c->twsi_phys, i2c->regsize); -fail_region: - kfree(i2c); out: return result; }; @@ -613,19 +615,24 @@ static int __devexit octeon_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); platform_set_drvdata(pdev, NULL); - free_irq(i2c->irq, i2c); - iounmap(i2c->twsi_base); - release_mem_region(i2c->twsi_phys, i2c->regsize); - kfree(i2c); return 0; }; +static struct of_device_id octeon_i2c_match[] = { + { + .compatible = "cavium,octeon-3860-twsi", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, octeon_i2c_match); + static struct platform_driver octeon_i2c_driver = { .probe = octeon_i2c_probe, .remove = __devexit_p(octeon_i2c_remove), .driver = { .owner = THIS_MODULE, .name = DRV_NAME, + .of_match_table = octeon_i2c_match, }, }; @@ -635,4 +642,3 @@ MODULE_AUTHOR("Michael Lawnick <michael.lawnick.ext@nsn.com>"); MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index a6fa884ae49..100b6775e17 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -52,9 +52,10 @@ #define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1) #define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1) +#define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa -#define JZ_NAND_MEM_ADDR_OFFSET 0x10000 #define JZ_NAND_MEM_CMD_OFFSET 0x08000 +#define JZ_NAND_MEM_ADDR_OFFSET 0x10000 struct jz_nand { struct mtd_info mtd; @@ -62,8 +63,11 @@ struct jz_nand { void __iomem *base; struct resource *mem; - void __iomem *bank_base; - struct resource *bank_mem; + unsigned char banks[JZ_NAND_NUM_BANKS]; + void __iomem *bank_base[JZ_NAND_NUM_BANKS]; + struct resource *bank_mem[JZ_NAND_NUM_BANKS]; + + int selected_bank; struct jz_nand_platform_data *pdata; bool is_reading; @@ -74,26 +78,50 @@ static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd) return container_of(mtd, struct jz_nand, mtd); } +static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr) +{ + struct jz_nand *nand = mtd_to_jz_nand(mtd); + struct nand_chip *chip = mtd->priv; + uint32_t ctrl; + int banknr; + + ctrl = readl(nand->base + JZ_REG_NAND_CTRL); + ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK; + + if (chipnr == -1) { + banknr = -1; + } else { + banknr = nand->banks[chipnr] - 1; + chip->IO_ADDR_R = nand->bank_base[banknr]; + chip->IO_ADDR_W = nand->bank_base[banknr]; + } + writel(ctrl, nand->base + JZ_REG_NAND_CTRL); + + nand->selected_bank = banknr; +} + static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) { struct jz_nand *nand = mtd_to_jz_nand(mtd); struct nand_chip *chip = mtd->priv; uint32_t reg; + void __iomem *bank_base = nand->bank_base[nand->selected_bank]; + + BUG_ON(nand->selected_bank < 0); if (ctrl & NAND_CTRL_CHANGE) { BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE)); if (ctrl & NAND_ALE) - chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_ADDR_OFFSET; + bank_base += JZ_NAND_MEM_ADDR_OFFSET; else if (ctrl & NAND_CLE) - chip->IO_ADDR_W = nand->bank_base + JZ_NAND_MEM_CMD_OFFSET; - else - chip->IO_ADDR_W = nand->bank_base; + bank_base += JZ_NAND_MEM_CMD_OFFSET; + chip->IO_ADDR_W = bank_base; reg = readl(nand->base + JZ_REG_NAND_CTRL); if (ctrl & NAND_NCE) - reg |= JZ_NAND_CTRL_ASSERT_CHIP(0); + reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); else - reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0); + reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); writel(reg, nand->base + JZ_REG_NAND_CTRL); } if (dat != NAND_CMD_NONE) @@ -252,7 +280,7 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, } static int jz_nand_ioremap_resource(struct platform_device *pdev, - const char *name, struct resource **res, void __iomem **base) + const char *name, struct resource **res, void *__iomem *base) { int ret; @@ -288,6 +316,90 @@ err: return ret; } +static inline void jz_nand_iounmap_resource(struct resource *res, void __iomem *base) +{ + iounmap(base); + release_mem_region(res->start, resource_size(res)); +} + +static int __devinit jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) { + int ret; + int gpio; + char gpio_name[9]; + char res_name[6]; + uint32_t ctrl; + struct mtd_info *mtd = &nand->mtd; + struct nand_chip *chip = &nand->chip; + + /* Request GPIO port. */ + gpio = JZ_GPIO_MEM_CS0 + bank - 1; + sprintf(gpio_name, "NAND CS%d", bank); + ret = gpio_request(gpio, gpio_name); + if (ret) { + dev_warn(&pdev->dev, + "Failed to request %s gpio %d: %d\n", + gpio_name, gpio, ret); + goto notfound_gpio; + } + + /* Request I/O resource. */ + sprintf(res_name, "bank%d", bank); + ret = jz_nand_ioremap_resource(pdev, res_name, + &nand->bank_mem[bank - 1], + &nand->bank_base[bank - 1]); + if (ret) + goto notfound_resource; + + /* Enable chip in bank. */ + jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0); + ctrl = readl(nand->base + JZ_REG_NAND_CTRL); + ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1); + writel(ctrl, nand->base + JZ_REG_NAND_CTRL); + + if (chipnr == 0) { + /* Detect first chip. */ + ret = nand_scan_ident(mtd, 1, NULL); + if (ret) + goto notfound_id; + + /* Retrieve the IDs from the first chip. */ + chip->select_chip(mtd, 0); + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + *nand_maf_id = chip->read_byte(mtd); + *nand_dev_id = chip->read_byte(mtd); + } else { + /* Detect additional chip. */ + chip->select_chip(mtd, chipnr); + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + if (*nand_maf_id != chip->read_byte(mtd) + || *nand_dev_id != chip->read_byte(mtd)) { + ret = -ENODEV; + goto notfound_id; + } + + /* Update size of the MTD. */ + chip->numchips++; + mtd->size += chip->chipsize; + } + + dev_info(&pdev->dev, "Found chip %i on bank %i\n", chipnr, bank); + return 0; + +notfound_id: + dev_info(&pdev->dev, "No chip found on bank %i\n", bank); + ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1)); + writel(ctrl, nand->base + JZ_REG_NAND_CTRL); + jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE); + jz_nand_iounmap_resource(nand->bank_mem[bank - 1], + nand->bank_base[bank - 1]); +notfound_resource: + gpio_free(gpio); +notfound_gpio: + return ret; +} + static int __devinit jz_nand_probe(struct platform_device *pdev) { int ret; @@ -295,6 +407,8 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) struct nand_chip *chip; struct mtd_info *mtd; struct jz_nand_platform_data *pdata = pdev->dev.platform_data; + size_t chipnr, bank_idx; + uint8_t nand_maf_id = 0, nand_dev_id = 0; nand = kzalloc(sizeof(*nand), GFP_KERNEL); if (!nand) { @@ -305,10 +419,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base); if (ret) goto err_free; - ret = jz_nand_ioremap_resource(pdev, "bank", &nand->bank_mem, - &nand->bank_base); - if (ret) - goto err_iounmap_mmio; if (pdata && gpio_is_valid(pdata->busy_gpio)) { ret = gpio_request(pdata->busy_gpio, "NAND busy pin"); @@ -316,7 +426,7 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to request busy gpio %d: %d\n", pdata->busy_gpio, ret); - goto err_iounmap_mem; + goto err_iounmap_mmio; } } @@ -339,22 +449,51 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) chip->chip_delay = 50; chip->cmd_ctrl = jz_nand_cmd_ctrl; + chip->select_chip = jz_nand_select_chip; if (pdata && gpio_is_valid(pdata->busy_gpio)) chip->dev_ready = jz_nand_dev_ready; - chip->IO_ADDR_R = nand->bank_base; - chip->IO_ADDR_W = nand->bank_base; - nand->pdata = pdata; platform_set_drvdata(pdev, nand); - writel(JZ_NAND_CTRL_ENABLE_CHIP(0), nand->base + JZ_REG_NAND_CTRL); - - ret = nand_scan_ident(mtd, 1, NULL); - if (ret) { - dev_err(&pdev->dev, "Failed to scan nand\n"); - goto err_gpio_free; + /* We are going to autodetect NAND chips in the banks specified in the + * platform data. Although nand_scan_ident() can detect multiple chips, + * it requires those chips to be numbered consecuitively, which is not + * always the case for external memory banks. And a fixed chip-to-bank + * mapping is not practical either, since for example Dingoo units + * produced at different times have NAND chips in different banks. + */ + chipnr = 0; + for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) { + unsigned char bank; + + /* If there is no platform data, look for NAND in bank 1, + * which is the most likely bank since it is the only one + * that can be booted from. + */ + bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1; + if (bank == 0) + break; + if (bank > JZ_NAND_NUM_BANKS) { + dev_warn(&pdev->dev, + "Skipping non-existing bank: %d\n", bank); + continue; + } + /* The detection routine will directly or indirectly call + * jz_nand_select_chip(), so nand->banks has to contain the + * bank we're checking. + */ + nand->banks[chipnr] = bank; + if (jz_nand_detect_bank(pdev, nand, bank, chipnr, + &nand_maf_id, &nand_dev_id) == 0) + chipnr++; + else + nand->banks[chipnr] = 0; + } + if (chipnr == 0) { + dev_err(&pdev->dev, "No NAND chips found\n"); + goto err_gpio_busy; } if (pdata && pdata->ident_callback) { @@ -364,8 +503,8 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) ret = nand_scan_tail(mtd); if (ret) { - dev_err(&pdev->dev, "Failed to scan nand\n"); - goto err_gpio_free; + dev_err(&pdev->dev, "Failed to scan NAND\n"); + goto err_unclaim_banks; } ret = mtd_device_parse_register(mtd, NULL, NULL, @@ -382,14 +521,21 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) return 0; err_nand_release: - nand_release(&nand->mtd); -err_gpio_free: + nand_release(mtd); +err_unclaim_banks: + while (chipnr--) { + unsigned char bank = nand->banks[chipnr]; + gpio_free(JZ_GPIO_MEM_CS0 + bank - 1); + jz_nand_iounmap_resource(nand->bank_mem[bank - 1], + nand->bank_base[bank - 1]); + } + writel(0, nand->base + JZ_REG_NAND_CTRL); +err_gpio_busy: + if (pdata && gpio_is_valid(pdata->busy_gpio)) + gpio_free(pdata->busy_gpio); platform_set_drvdata(pdev, NULL); - gpio_free(pdata->busy_gpio); -err_iounmap_mem: - iounmap(nand->bank_base); err_iounmap_mmio: - iounmap(nand->base); + jz_nand_iounmap_resource(nand->mem, nand->base); err_free: kfree(nand); return ret; @@ -398,16 +544,26 @@ err_free: static int __devexit jz_nand_remove(struct platform_device *pdev) { struct jz_nand *nand = platform_get_drvdata(pdev); + struct jz_nand_platform_data *pdata = pdev->dev.platform_data; + size_t i; nand_release(&nand->mtd); /* Deassert and disable all chips */ writel(0, nand->base + JZ_REG_NAND_CTRL); - iounmap(nand->bank_base); - release_mem_region(nand->bank_mem->start, resource_size(nand->bank_mem)); - iounmap(nand->base); - release_mem_region(nand->mem->start, resource_size(nand->mem)); + for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) { + unsigned char bank = nand->banks[i]; + if (bank != 0) { + jz_nand_iounmap_resource(nand->bank_mem[bank - 1], + nand->bank_base[bank - 1]); + gpio_free(JZ_GPIO_MEM_CS0 + bank - 1); + } + } + if (pdata && gpio_is_valid(pdata->busy_gpio)) + gpio_free(pdata->busy_gpio); + + jz_nand_iounmap_resource(nand->mem, nand->base); platform_set_drvdata(pdev, NULL); kfree(nand); diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c index cd827ff4a02..c42bbb16cda 100644 --- a/drivers/net/ethernet/octeon/octeon_mgmt.c +++ b/drivers/net/ethernet/octeon/octeon_mgmt.c @@ -6,19 +6,21 @@ * Copyright (C) 2009 Cavium Networks */ -#include <linux/capability.h> +#include <linux/platform_device.h> #include <linux/dma-mapping.h> -#include <linux/init.h> -#include <linux/module.h> +#include <linux/etherdevice.h> +#include <linux/capability.h> #include <linux/interrupt.h> -#include <linux/platform_device.h> #include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/if.h> +#include <linux/spinlock.h> #include <linux/if_vlan.h> +#include <linux/of_mdio.h> +#include <linux/module.h> +#include <linux/of_net.h> +#include <linux/init.h> #include <linux/slab.h> #include <linux/phy.h> -#include <linux/spinlock.h> +#include <linux/io.h> #include <asm/octeon/octeon.h> #include <asm/octeon/cvmx-mixx-defs.h> @@ -58,8 +60,56 @@ union mgmt_port_ring_entry { } s; }; +#define MIX_ORING1 0x0 +#define MIX_ORING2 0x8 +#define MIX_IRING1 0x10 +#define MIX_IRING2 0x18 +#define MIX_CTL 0x20 +#define MIX_IRHWM 0x28 +#define MIX_IRCNT 0x30 +#define MIX_ORHWM 0x38 +#define MIX_ORCNT 0x40 +#define MIX_ISR 0x48 +#define MIX_INTENA 0x50 +#define MIX_REMCNT 0x58 +#define MIX_BIST 0x78 + +#define AGL_GMX_PRT_CFG 0x10 +#define AGL_GMX_RX_FRM_CTL 0x18 +#define AGL_GMX_RX_FRM_MAX 0x30 +#define AGL_GMX_RX_JABBER 0x38 +#define AGL_GMX_RX_STATS_CTL 0x50 + +#define AGL_GMX_RX_STATS_PKTS_DRP 0xb0 +#define AGL_GMX_RX_STATS_OCTS_DRP 0xb8 +#define AGL_GMX_RX_STATS_PKTS_BAD 0xc0 + +#define AGL_GMX_RX_ADR_CTL 0x100 +#define AGL_GMX_RX_ADR_CAM_EN 0x108 +#define AGL_GMX_RX_ADR_CAM0 0x180 +#define AGL_GMX_RX_ADR_CAM1 0x188 +#define AGL_GMX_RX_ADR_CAM2 0x190 +#define AGL_GMX_RX_ADR_CAM3 0x198 +#define AGL_GMX_RX_ADR_CAM4 0x1a0 +#define AGL_GMX_RX_ADR_CAM5 0x1a8 + +#define AGL_GMX_TX_STATS_CTL 0x268 +#define AGL_GMX_TX_CTL 0x270 +#define AGL_GMX_TX_STAT0 0x280 +#define AGL_GMX_TX_STAT1 0x288 +#define AGL_GMX_TX_STAT2 0x290 +#define AGL_GMX_TX_STAT3 0x298 +#define AGL_GMX_TX_STAT4 0x2a0 +#define AGL_GMX_TX_STAT5 0x2a8 +#define AGL_GMX_TX_STAT6 0x2b0 +#define AGL_GMX_TX_STAT7 0x2b8 +#define AGL_GMX_TX_STAT8 0x2c0 +#define AGL_GMX_TX_STAT9 0x2c8 + struct octeon_mgmt { struct net_device *netdev; + u64 mix; + u64 agl; int port; int irq; u64 *tx_ring; @@ -85,31 +135,34 @@ struct octeon_mgmt { struct napi_struct napi; struct tasklet_struct tx_clean_tasklet; struct phy_device *phydev; + struct device_node *phy_np; + resource_size_t mix_phys; + resource_size_t mix_size; + resource_size_t agl_phys; + resource_size_t agl_size; }; static void octeon_mgmt_set_rx_irq(struct octeon_mgmt *p, int enable) { - int port = p->port; union cvmx_mixx_intena mix_intena; unsigned long flags; spin_lock_irqsave(&p->lock, flags); - mix_intena.u64 = cvmx_read_csr(CVMX_MIXX_INTENA(port)); + mix_intena.u64 = cvmx_read_csr(p->mix + MIX_INTENA); mix_intena.s.ithena = enable ? 1 : 0; - cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64); + cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64); spin_unlock_irqrestore(&p->lock, flags); } static void octeon_mgmt_set_tx_irq(struct octeon_mgmt *p, int enable) { - int port = p->port; union cvmx_mixx_intena mix_intena; unsigned long flags; spin_lock_irqsave(&p->lock, flags); - mix_intena.u64 = cvmx_read_csr(CVMX_MIXX_INTENA(port)); + mix_intena.u64 = cvmx_read_csr(p->mix + MIX_INTENA); mix_intena.s.othena = enable ? 1 : 0; - cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64); + cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64); spin_unlock_irqrestore(&p->lock, flags); } @@ -146,7 +199,6 @@ static unsigned int ring_size_to_bytes(unsigned int ring_size) static void octeon_mgmt_rx_fill_ring(struct net_device *netdev) { struct octeon_mgmt *p = netdev_priv(netdev); - int port = p->port; while (p->rx_current_fill < ring_max_fill(OCTEON_MGMT_RX_RING_SIZE)) { unsigned int size; @@ -177,24 +229,23 @@ static void octeon_mgmt_rx_fill_ring(struct net_device *netdev) (p->rx_next_fill + 1) % OCTEON_MGMT_RX_RING_SIZE; p->rx_current_fill++; /* Ring the bell. */ - cvmx_write_csr(CVMX_MIXX_IRING2(port), 1); + cvmx_write_csr(p->mix + MIX_IRING2, 1); } } static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p) { - int port = p->port; union cvmx_mixx_orcnt mix_orcnt; union mgmt_port_ring_entry re; struct sk_buff *skb; int cleaned = 0; unsigned long flags; - mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port)); + mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT); while (mix_orcnt.s.orcnt) { spin_lock_irqsave(&p->tx_list.lock, flags); - mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port)); + mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT); if (mix_orcnt.s.orcnt == 0) { spin_unlock_irqrestore(&p->tx_list.lock, flags); @@ -214,7 +265,7 @@ static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p) mix_orcnt.s.orcnt = 1; /* Acknowledge to hardware that we have the buffer. */ - cvmx_write_csr(CVMX_MIXX_ORCNT(port), mix_orcnt.u64); + cvmx_write_csr(p->mix + MIX_ORCNT, mix_orcnt.u64); p->tx_current_fill--; spin_unlock_irqrestore(&p->tx_list.lock, flags); @@ -224,7 +275,7 @@ static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p) dev_kfree_skb_any(skb); cleaned++; - mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port)); + mix_orcnt.u64 = cvmx_read_csr(p->mix + MIX_ORCNT); } if (cleaned && netif_queue_stopped(p->netdev)) @@ -241,13 +292,12 @@ static void octeon_mgmt_clean_tx_tasklet(unsigned long arg) static void octeon_mgmt_update_rx_stats(struct net_device *netdev) { struct octeon_mgmt *p = netdev_priv(netdev); - int port = p->port; unsigned long flags; u64 drop, bad; /* These reads also clear the count registers. */ - drop = cvmx_read_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_DRP(port)); - bad = cvmx_read_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_BAD(port)); + drop = cvmx_read_csr(p->agl + AGL_GMX_RX_STATS_PKTS_DRP); + bad = cvmx_read_csr(p-> |