diff options
author | Albert ARIBAUD <albert.u.boot@aribaud.net> | 2015-10-14 10:46:36 +0200 |
---|---|---|
committer | Albert ARIBAUD <albert.u.boot@aribaud.net> | 2015-10-14 10:46:36 +0200 |
commit | 13a3972585af60ec367d209cedbd3601e0c77467 (patch) | |
tree | 4b3312669b3e501f6bc10b39d8c7bbf516f07aac /drivers | |
parent | 208bd51396fb606dbdcf45b064e6b372d7dd3e81 (diff) | |
parent | 297faccca2235e359012118495b9b73451d54bb9 (diff) |
Merge remote-tracking branch 'u-boot/master'
Diffstat (limited to 'drivers')
85 files changed, 3649 insertions, 1470 deletions
diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index 0d19dd25a3..82c68439f8 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -15,6 +15,7 @@ #include <asm/errno.h> #include <asm/io.h> #include <malloc.h> +#include <memalign.h> #include <scsi.h> #include <libata.h> #include <linux/ctype.h> diff --git a/drivers/core/device.c b/drivers/core/device.c index 0ccd443f25..833a803696 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -289,8 +289,12 @@ int device_probe_child(struct udevice *dev, void *parent_priv) dev->flags |= DM_FLAG_ACTIVATED; - /* continue regardless of the result of pinctrl */ - pinctrl_select_state(dev, "default"); + /* + * Process pinctrl for everything except the root device, and + * continue regardless of the result of pinctrl. + */ + if (dev->parent) + pinctrl_select_state(dev, "default"); ret = uclass_pre_probe_device(dev); if (ret) @@ -581,7 +585,10 @@ fdt_addr_t dev_get_addr(struct udevice *dev) #if CONFIG_IS_ENABLED(OF_CONTROL) fdt_addr_t addr; - addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); + addr = fdtdec_get_addr_size_auto_parent(gd->fdt_blob, + dev->parent->of_offset, + dev->of_offset, "reg", + 0, NULL); if (CONFIG_IS_ENABLED(SIMPLE_BUS) && addr != FDT_ADDR_T_NONE) { if (device_get_uclass_id(dev->parent) == UCLASS_SIMPLE_BUS) addr = simple_bus_translate(dev->parent, addr); diff --git a/drivers/ddr/marvell/a38x/ddr3_init.h b/drivers/ddr/marvell/a38x/ddr3_init.h index e2ff040b00..cb3fb24416 100644 --- a/drivers/ddr/marvell/a38x/ddr3_init.h +++ b/drivers/ddr/marvell/a38x/ddr3_init.h @@ -32,8 +32,6 @@ */ #define MV_DEBUG_INIT -#define BIT(x) (1 << (x)) - #ifdef MV_DEBUG_INIT #define DEBUG_INIT_S(s) puts(s) #define DEBUG_INIT_D(d, l) printf("%x", d) diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index 6cf240de22..8f5915e49c 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -164,7 +164,6 @@ static int dfu_write_buffer_drain(struct dfu_entity *dfu) void dfu_write_transaction_cleanup(struct dfu_entity *dfu) { /* clear everything */ - dfu_free_buf(); dfu->crc = 0; dfu->offset = 0; dfu->i_blk_seq_num = 0; @@ -339,17 +338,6 @@ int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) dfu->r_left = dfu->get_medium_size(dfu); if (dfu->r_left < 0) return dfu->r_left; - switch (dfu->layout) { - case DFU_RAW_ADDR: - case DFU_RAM_ADDR: - break; - default: - if (dfu->r_left > dfu_buf_size) { - printf("%s: File too big for buffer\n", - __func__); - return -EOVERFLOW; - } - } debug("%s: %s %ld [B]\n", __func__, dfu->name, dfu->r_left); @@ -385,7 +373,6 @@ int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) dfu_hash_algo->name, dfu->crc); puts("\nUPLOAD ... done\nCtrl+C to exit ...\n"); - dfu_free_buf(); dfu->i_blk_seq_num = 0; dfu->crc = 0; dfu->offset = 0; @@ -433,6 +420,7 @@ static int dfu_fill_entity(struct dfu_entity *dfu, char *s, int alt, __func__, interface); return -1; } + dfu_get_buf(dfu); return 0; } @@ -441,6 +429,7 @@ void dfu_free_entities(void) { struct dfu_entity *dfu, *p, *t = NULL; + dfu_free_buf(); list_for_each_entry_safe_reverse(dfu, p, &dfu_list, list) { list_del(&dfu->list); if (dfu->free_entity) diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index 2a780f7b5d..5a9fb4a6e2 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -18,6 +18,7 @@ static unsigned char *dfu_file_buf; static long dfu_file_buf_len; +static long dfu_file_buf_filled; static int mmc_access_part(struct dfu_entity *dfu, struct mmc *mmc, int part) { @@ -230,9 +231,12 @@ long dfu_get_medium_size_mmc(struct dfu_entity *dfu) return dfu->data.mmc.lba_size * dfu->data.mmc.lba_blk_size; case DFU_FS_FAT: case DFU_FS_EXT4: + dfu_file_buf_filled = -1; ret = mmc_file_op(DFU_OP_SIZE, dfu, NULL, &len); if (ret < 0) return ret; + if (len > CONFIG_SYS_DFU_MAX_FILE_SIZE) + return -1; return len; default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, @@ -241,6 +245,27 @@ long dfu_get_medium_size_mmc(struct dfu_entity *dfu) } } +static int mmc_file_unbuffer(struct dfu_entity *dfu, u64 offset, void *buf, + long *len) +{ + int ret; + long file_len; + + if (dfu_file_buf_filled == -1) { + ret = mmc_file_op(DFU_OP_READ, dfu, dfu_file_buf, &file_len); + if (ret < 0) + return ret; + dfu_file_buf_filled = file_len; + } + if (offset + *len > dfu_file_buf_filled) + return -EINVAL; + + /* Add to the current buffer. */ + memcpy(buf, dfu_file_buf + offset, *len); + + return 0; +} + int dfu_read_medium_mmc(struct dfu_entity *dfu, u64 offset, void *buf, long *len) { @@ -252,7 +277,7 @@ int dfu_read_medium_mmc(struct dfu_entity *dfu, u64 offset, void *buf, break; case DFU_FS_FAT: case DFU_FS_EXT4: - ret = mmc_file_op(DFU_OP_READ, dfu, buf, len); + ret = mmc_file_unbuffer(dfu, offset, buf, len); break; default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, diff --git a/drivers/gpio/lpc32xx_gpio.c b/drivers/gpio/lpc32xx_gpio.c index 8a9826e6eb..9674ee75f0 100644 --- a/drivers/gpio/lpc32xx_gpio.c +++ b/drivers/gpio/lpc32xx_gpio.c @@ -22,7 +22,7 @@ * read on another one. * * In order to keep this code simple, GPIOS are considered here as - * homogeneous and linear, from 0 to 127. + * homogeneous and linear, from 0 to 159. * * ** WARNING #1 ** * @@ -35,7 +35,7 @@ * Please read NOTE in description of lpc32xx_gpio_get_function(). */ -#define LPC32XX_GPIOS 128 +#define LPC32XX_GPIOS 160 struct lpc32xx_gpio_priv { struct gpio_regs *regs; @@ -45,11 +45,18 @@ struct lpc32xx_gpio_priv { /** * We have 4 GPIO ports of 32 bits each + * + * Port mapping offset (32 bits each): + * - Port 0: 0 + * - Port 1: 32 + * - Port 2: 64 + * - Port 3: GPO / GPIO (output): 96 + * - Port 3: GPI: 128 */ -#define MAX_GPIO 128 +#define MAX_GPIO 160 -#define GPIO_TO_PORT(gpio) ((gpio / 32) & 3) +#define GPIO_TO_PORT(gpio) ((gpio / 32) & 7) #define GPIO_TO_RANK(gpio) (gpio % 32) #define GPIO_TO_MASK(gpio) (1 << (gpio % 32)) @@ -75,9 +82,16 @@ static int lpc32xx_gpio_direction_input(struct udevice *dev, unsigned offset) break; case 2: /* ports 2 and 3 share a common direction */ - case 3: writel(mask, ®s->p2_p3_dir_clr); break; + case 3: + /* Setup direction only for GPIO_xx. */ + if ((mask >= 25) && (mask <= 30)) + writel(mask, ®s->p2_p3_dir_clr); + break; + case 4: + /* GPI_xx; nothing to do. */ + break; default: return -1; } @@ -111,6 +125,11 @@ static int lpc32xx_gpio_get_value(struct udevice *dev, unsigned offset) value = readl(®s->p2_inp_state); break; case 3: + /* Read GPO_xx and GPIO_xx (as output) using p3_outp_state. */ + value = readl(®s->p3_outp_state); + break; + case 4: + /* Read GPI_xx and GPIO_xx (as input) using p3_inp_state. */ value = readl(®s->p3_inp_state); break; default: @@ -149,6 +168,8 @@ static int gpio_set(struct udevice *dev, unsigned gpio) case 3: writel(mask, ®s->p3_outp_set); break; + case 4: + /* GPI_xx; invalid. */ default: return -1; } @@ -181,6 +202,8 @@ static int gpio_clr(struct udevice *dev, unsigned gpio) case 3: writel(mask, ®s->p3_outp_clr); break; + case 4: + /* GPI_xx; invalid. */ default: return -1; } @@ -223,9 +246,15 @@ static int lpc32xx_gpio_direction_output(struct udevice *dev, unsigned offset, break; case 2: /* ports 2 and 3 share a common direction */ - case 3: writel(mask, ®s->p2_p3_dir_set); break; + case 3: + /* Setup direction only for GPIO_xx. */ + if ((mask >= 25) && (mask <= 30)) + writel(mask, ®s->p2_p3_dir_set); + break; + case 4: + /* GPI_xx; invalid. */ default: return -1; } diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c index 17fcfbf4d3..0f22b238ba 100644 --- a/drivers/gpio/s5p_gpio.c +++ b/drivers/gpio/s5p_gpio.c @@ -341,18 +341,22 @@ static int gpio_exynos_bind(struct udevice *parent) plat = calloc(1, sizeof(*plat)); if (!plat) return -ENOMEM; - reg = fdtdec_get_addr(blob, node, "reg"); - if (reg != FDT_ADDR_T_NONE) - bank = (struct s5p_gpio_bank *)((ulong)base + reg); - plat->bank = bank; - plat->bank_name = fdt_get_name(blob, node, NULL); - debug("dev at %p: %s\n", bank, plat->bank_name); + plat->bank_name = fdt_get_name(blob, node, NULL); ret = device_bind(parent, parent->driver, - plat->bank_name, plat, -1, &dev); + plat->bank_name, plat, -1, &dev); if (ret) return ret; + dev->of_offset = node; + + reg = dev_get_addr(dev); + if (reg != FDT_ADDR_T_NONE) + bank = (struct s5p_gpio_bank *)((ulong)base + reg); + + plat->bank = bank; + + debug("dev at %p: %s\n", bank, plat->bank_name); } return 0; diff --git a/drivers/gpio/sh_pfc.c b/drivers/gpio/sh_pfc.c index 7a5af20a2a..a0eac137c2 100644 --- a/drivers/gpio/sh_pfc.c +++ b/drivers/gpio/sh_pfc.c @@ -75,7 +75,8 @@ static int gpio_read_bit(struct pinmux_data_reg *dr, debug("read_bit: addr = %lx, pos = %ld, " "r_width = %ld\n", dr->reg, pos, dr->reg_width); - return (gpio_read_raw_reg(dr->mapped_reg, dr->reg_width) >> pos) & 1; + return + (gpio_read_raw_reg(dr->mapped_reg + 0x4, dr->reg_width) >> pos) & 1; } static void gpio_write_bit(struct pinmux_data_reg *dr, diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c index 4921f0ff42..8e880e276f 100644 --- a/drivers/gpio/tegra_gpio.c +++ b/drivers/gpio/tegra_gpio.c @@ -1,6 +1,6 @@ /* * NVIDIA Tegra20 GPIO handling. - * (C) Copyright 2010-2012 + * (C) Copyright 2010-2012,2015 * NVIDIA Corporation <www.nvidia.com> * * SPDX-License-Identifier: GPL-2.0+ @@ -25,12 +25,10 @@ DECLARE_GLOBAL_DATA_PTR; -enum { - TEGRA_CMD_INFO, - TEGRA_CMD_PORT, - TEGRA_CMD_OUTPUT, - TEGRA_CMD_INPUT, -}; +static const int CONFIG_SFIO = 0; +static const int CONFIG_GPIO = 1; +static const int DIRECTION_INPUT = 0; +static const int DIRECTION_OUTPUT = 1; struct tegra_gpio_platdata { struct gpio_ctlr_bank *bank; @@ -44,7 +42,7 @@ struct tegra_port_info { int base_gpio; /* Port number for this port (0, 1,.., n-1) */ }; -/* Return config of pin 'gpio' as GPIO (1) or SFPIO (0) */ +/* Return config of pin 'gpio' as GPIO (1) or SFIO (0) */ static int get_config(unsigned gpio) { struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; @@ -53,15 +51,15 @@ static int get_config(unsigned gpio) int type; u = readl(&bank->gpio_config[GPIO_PORT(gpio)]); - type = (u >> GPIO_BIT(gpio)) & 1; + type = (u >> GPIO_BIT(gpio)) & 1; debug("get_config: port = %d, bit = %d is %s\n", GPIO_FULLPORT(gpio), GPIO_BIT(gpio), type ? "GPIO" : "SFPIO"); - return type; + return type ? CONFIG_GPIO : CONFIG_SFIO; } -/* Config pin 'gpio' as GPIO or SFPIO, based on 'type' */ +/* Config pin 'gpio' as GPIO or SFIO, based on 'type' */ static void set_config(unsigned gpio, int type) { struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE; @@ -72,7 +70,7 @@ static void set_config(unsigned gpio, int type) GPIO_FULLPORT(gpio), GPIO_BIT(gpio), type ? "GPIO" : "SFPIO"); u = readl(&bank->gpio_config[GPIO_PORT(gpio)]); - if (type) /* GPIO */ + if (type != CONFIG_SFIO) u |= 1 << GPIO_BIT(gpio); else u &= ~(1 << GPIO_BIT(gpio)); @@ -93,7 +91,7 @@ static int get_direction(unsigned gpio) debug("get_direction: port = %d, bit = %d, %s\n", GPIO_FULLPORT(gpio), GPIO_BIT(gpio), dir ? "OUT" : "IN"); - return dir; + return dir ? DIRECTION_OUTPUT : DIRECTION_INPUT; } /* Config GPIO pin 'gpio' as input or output (OE) as per 'output' */ @@ -107,7 +105,7 @@ static void set_direction(unsigned gpio, int output) GPIO_FULLPORT(gpio), GPIO_BIT(gpio), output ? "OUT" : "IN"); u = readl(&bank->gpio_dir_out[GPIO_PORT(gpio)]); - if (output) + if (output != DIRECTION_INPUT) u |= 1 << GPIO_BIT(gpio); else u &= ~(1 << GPIO_BIT(gpio)); @@ -136,24 +134,16 @@ static void set_level(unsigned gpio, int high) * Generic_GPIO primitives. */ -static int tegra_gpio_request(struct udevice *dev, unsigned offset, - const char *label) -{ - struct tegra_port_info *state = dev_get_priv(dev); - - /* Configure as a GPIO */ - set_config(state->base_gpio + offset, 1); - - return 0; -} - /* set GPIO pin 'gpio' as an input */ static int tegra_gpio_direction_input(struct udevice *dev, unsigned offset) { struct tegra_port_info *state = dev_get_priv(dev); /* Configure GPIO direction as input. */ - set_direction(state->base_gpio + offset, 0); + set_direction(state->base_gpio + offset, DIRECTION_INPUT); + + /* Enable the pin as a GPIO */ + set_config(state->base_gpio + offset, 1); return 0; } @@ -169,7 +159,10 @@ static int tegra_gpio_direction_output(struct udevice *dev, unsigned offset, set_level(gpio, value); /* Configure GPIO direction as output. */ - set_direction(gpio, 1); + set_direction(gpio, DIRECTION_OUTPUT); + + /* Enable the pin as a GPIO */ + set_config(state->base_gpio + offset, 1); return 0; } @@ -211,16 +204,18 @@ void gpio_config_table(const struct tegra_gpio_config *config, int len) for (i = 0; i < len; i++) { switch (config[i].init) { case TEGRA_GPIO_INIT_IN: - gpio_direction_input(config[i].gpio); + set_direction(config[i].gpio, DIRECTION_INPUT); break; case TEGRA_GPIO_INIT_OUT0: - gpio_direction_output(config[i].gpio, 0); + set_level(config[i].gpio, 0); + set_direction(config[i].gpio, DIRECTION_OUTPUT); break; case TEGRA_GPIO_INIT_OUT1: - gpio_direction_output(config[i].gpio, 1); + set_level(config[i].gpio, 1); + set_direction(config[i].gpio, DIRECTION_OUTPUT); break; } - set_config(config[i].gpio, 1); + set_config(config[i].gpio, CONFIG_GPIO); } } @@ -254,7 +249,6 @@ static int tegra_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, } static const struct dm_gpio_ops gpio_tegra_ops = { - .request = tegra_gpio_request, .direction_input = tegra_gpio_direction_input, .direction_output = tegra_gpio_direction_output, .get_value = tegra_gpio_get_value, diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 8ce294b02a..32198bd5b2 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -14,7 +14,6 @@ obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o obj-$(CONFIG_I2C_MV) += mv_i2c.o obj-$(CONFIG_PCA9564_I2C) += pca9564_i2c.o obj-$(CONFIG_TSI108_I2C) += tsi108_i2c.o -obj-$(CONFIG_U8500_I2C) += u8500_i2c.o obj-$(CONFIG_SH_SH7734_I2C) += sh_sh7734_i2c.o obj-$(CONFIG_SYS_I2C) += i2c_core.o obj-$(CONFIG_SYS_I2C_DAVINCI) += davinci_i2c.o diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index f1056e21a2..0f977d706d 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -612,16 +612,22 @@ static u32 mxc_i2c_set_bus_speed(struct i2c_adapter *adap, uint speed) /* * Register mxc i2c adapters */ +#ifdef CONFIG_SYS_I2C_MXC_I2C1 U_BOOT_I2C_ADAP_COMPLETE(mxc0, mxc_i2c_init, mxc_i2c_probe, mxc_i2c_read, mxc_i2c_write, mxc_i2c_set_bus_speed, CONFIG_SYS_MXC_I2C1_SPEED, CONFIG_SYS_MXC_I2C1_SLAVE, 0) +#endif + +#ifdef CONFIG_SYS_I2C_MXC_I2C2 U_BOOT_I2C_ADAP_COMPLETE(mxc1, mxc_i2c_init, mxc_i2c_probe, mxc_i2c_read, mxc_i2c_write, mxc_i2c_set_bus_speed, CONFIG_SYS_MXC_I2C2_SPEED, CONFIG_SYS_MXC_I2C2_SLAVE, 1) +#endif + #ifdef CONFIG_SYS_I2C_MXC_I2C3 U_BOOT_I2C_ADAP_COMPLETE(mxc2, mxc_i2c_init, mxc_i2c_probe, mxc_i2c_read, mxc_i2c_write, diff --git a/drivers/i2c/u8500_i2c.c b/drivers/i2c/u8500_i2c.c deleted file mode 100644 index 81ffb8ed79..0000000000 --- a/drivers/i2c/u8500_i2c.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * - * Basic U-Boot I2C interface for STn8500/DB8500 - * Author: Michael Brandt <Michael.Brandt@stericsson.com> for ST-Ericsson - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -/* - * Only 7-bit I2C device addresses are supported. - */ - -#include <common.h> -#include <i2c.h> - -#include "u8500_i2c.h" -#include <asm/io.h> -#include <asm/arch/clock.h> - -#define U8500_I2C_ENDAD_COUNTER (CONFIG_SYS_HZ/100) /* I2C bus timeout */ -#define U8500_I2C_FIFO_FLUSH_COUNTER 500000 /* flush "timeout" */ -#define U8500_I2C_SCL_FREQ 100000 /* I2C bus clock freq */ -#define U8500_I2C_INPUT_FREQ 48000000 /* Input clock freq */ -#define TX_FIFO_THRESHOLD 0x4 -#define RX_FIFO_THRESHOLD 0x4 -#define SLAVE_SETUP_TIME 14 /* Slave data setup time, 250ns for 48MHz i2c_clk */ - -#define WRITE_FIELD(var, mask, shift, value) \ - (var = ((var & ~(mask)) | ((value) << (shift)))) - -static unsigned int bus_initialized[CONFIG_SYS_U8500_I2C_BUS_MAX]; -static unsigned int i2c_bus_num; -static unsigned int i2c_bus_speed[] = { - CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SPEED, - CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SPEED -}; -static struct u8500_i2c_regs *i2c_dev[] = { - (struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C0_BASE, - (struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C1_BASE, - (struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C2_BASE, - (struct u8500_i2c_regs *)CONFIG_SYS_U8500_I2C3_BASE, -}; - -static struct { - int periph; - int pcken; - int kcken; -} i2c_clock_bits[] = { - {3, 3, 3}, /* I2C0 */ - {1, 2, 2}, /* I2C1 */ - {1, 6, 6}, /* I2C2 */ - {2, 0, 0}, /* I2C3 */ -}; - -static void i2c_set_bit(void *reg, u32 mask) -{ - writel(readl(reg) | mask, reg); -} - -static void i2c_clr_bit(void *reg, u32 mask) -{ - writel(readl(reg) & ~mask, reg); -} - -static void i2c_write_field(void *reg, u32 mask, uint shift, u32 value) -{ - writel((readl(reg) & ~mask) | (value << shift), reg); -} - -static int __i2c_set_bus_speed(unsigned int speed) -{ - u32 value; - struct u8500_i2c_regs *i2c_regs; - - i2c_regs = i2c_dev[i2c_bus_num]; - - /* Select standard (100 kbps) speed mode */ - i2c_write_field(&i2c_regs->cr, U8500_I2C_CR_SM, - U8500_I2C_CR_SHIFT_SM, 0x0); - - /* - * Set the Baud Rate Counter 2 value - * Baud rate (standard) = fi2cclk / ( (BRCNT2 x 2) + Foncycle ) - * Foncycle = 0 (no digital filtering) - */ - value = (u32) (U8500_I2C_INPUT_FREQ / (speed * 2)); - i2c_write_field(&i2c_regs->brcr, U8500_I2C_BRCR_BRCNT2, - U8500_I2C_BRCR_SHIFT_BRCNT2, value); - - /* ensure that BRCNT value is zero */ - i2c_write_field(&i2c_regs->brcr, U8500_I2C_BRCR_BRCNT1, - U8500_I2C_BRCR_SHIFT_BRCNT1, 0); - - return U8500_I2C_INPUT_FREQ/(value * 2); -} - -/* - * i2c_init - initialize the i2c bus - * - * speed: bus speed (in HZ) - * slaveaddr: address of device in slave mode - * - * Slave mode is not implemented. - */ -void i2c_init(int speed, int slaveaddr) -{ - struct u8500_i2c_regs *i2c_regs; - - debug("i2c_init bus %d, speed %d\n", i2c_bus_num, speed); - - u8500_clock_enable(i2c_clock_bits[i2c_bus_num].periph, - i2c_clock_bits[i2c_bus_num].pcken, - i2c_clock_bits[i2c_bus_num].kcken); - - i2c_regs = i2c_dev[i2c_bus_num]; - - /* Disable the controller */ - i2c_clr_bit(&i2c_regs->cr, U8500_I2C_CR_PE); - - /* Clear registers */ - writel(0, &i2c_regs->cr); - writel(0, &i2c_regs->scr); - writel(0, &i2c_regs->hsmcr); - writel(0, &i2c_regs->tftr); - writel(0, &i2c_regs->rftr); - writel(0, &i2c_regs->dmar); - - i2c_bus_speed[i2c_bus_num] = __i2c_set_bus_speed(speed); - - /* - * Set our own address. - * Set slave address mode to 7 bit addressing mode - */ - i2c_clr_bit(&i2c_regs->cr, U8500_I2C_CR_SAM); - i2c_write_field(&i2c_regs->scr, U8500_I2C_SCR_ADDR, - U8500_I2C_SCR_SHIFT_ADDR, slaveaddr); - /* Slave Data Set up Time */ - i2c_write_field(&i2c_regs->scr, U8500_I2C_SCR_DATA_SETUP_TIME, - U8500_I2C_SCR_SHIFT_DATA_SETUP_TIME, SLAVE_SETUP_TIME); - - /* Disable the DMA sync logic */ - i2c_write_field(&i2c_regs->cr, U8500_I2C_CR_DMA_SLE, - U8500_I2C_CR_SHIFT_DMA_SLE, 0); - - /* Disable interrupts */ - writel(0, &i2c_regs->imscr); - - /* Configure bus master mode */ - i2c_write_field(&i2c_regs->cr, U8500_I2C_CR_OM, U8500_I2C_CR_SHIFT_OM, - U8500_I2C_BUS_MASTER_MODE); - /* Set FIFO threshold values */ - writel(TX_FIFO_THRESHOLD, &i2c_regs->tftr); - writel(RX_FIFO_THRESHOLD, &i2c_regs->rftr); - - /* Enable the I2C Controller */ - i2c_set_bit(&i2c_regs->cr, U8500_I2C_CR_PE); - - bus_initialized[i2c_bus_num] = 1; -} - - -/* - * loop_till_bit_clear - polls on a bit till it clears - * ioreg: register where you want to check status - * mask: bit mask for the bit you wish to check - * timeout: timeout in ticks/s - */ -static int loop_till_bit_clear(void *io_reg, u32 mask, unsigned long timeout) -{ - unsigned long timebase = get_timer(0); - - do { - if ((readl(io_reg) & mask) == 0x0UL) - return 0; - } while (get_timer(timebase) < timeout); - - debug("loop_till_bit_clear timed out\n"); - return -1; -} - -/* - * loop_till_bit_set - polls on a bit till it is set. - * ioreg: register where you want to check status - * mask: bit mask for the bit you wish to check - * timeout: timeout in ticks/s - */ -static int loop_till_bit_set(void *io_reg, u32 mask, unsigned long timeout) -{ - unsigned long timebase = get_timer(0); - - do { - if ((readl(io_reg) & mask) != 0x0UL) - return 0; - } while (get_timer(timebase) < timeout); - - debug("loop_till_bit_set timed out\n"); - return -1; -} - -/* - * flush_fifo - flush the I2C TX and RX FIFOs - */ -static void flush_fifo(struct u8500_i2c_regs *i2c_regs) -{ - int counter = U8500_I2C_FIFO_FLUSH_COUNTER; - - /* Flush Tx FIFO */ - i2c_set_bit(&i2c_regs->cr, U8500_I2C_CR_FTX); - /* Flush Rx FIFO */ - i2c_set_bit(&i2c_regs->cr, U8500_I2C_CR_FRX); - while (counter--) { - if (!(readl(&i2c_regs->cr) & - (U8500_I2C_CR_FTX | U8500_I2C_CR_FRX))) - break; - } - return; -} - -#ifdef DEBUG -static void print_abort_reason(struct u8500_i2c_regs *i2c_regs) -{ - int cause; - - printf("abort: risr %08x, sr %08x\n", i2c_regs->risr, i2c_regs->sr); - cause = (readl(&i2c_regs->sr) & U8500_I2C_SR_CAUSE) >> - U8500_I2C_SR_SHIFT_CAUSE; - switch (cause) { - case U8500_I2C_NACK_ADDR: - printf("No Ack received after Slave Address xmission\n"); - break; - case U8500_I2C_NACK_DATA: - printf("Valid for MASTER_WRITE: No Ack received " - "during data phase\n"); - break; - case U8500_I2C_ACK_MCODE: - printf("Master recv ack after xmission of master code" - "in hs mode\n"); - break; - case U8500_I2C_ARB_LOST: - printf("Master Lost arbitration\n"); - break; - case U8500_I2C_BERR_START: - printf("Slave restarts\n"); - break; - case U8500_I2C_BERR_STOP: - printf("Slave reset\n"); - break; - case U8500_I2C_OVFL: - printf("Overflow\n"); - break; - default: - printf("Unknown error type\n"); - } -} -#endif - -/* - * i2c_abort - called when a I2C transaction failed - */ -static void i2c_abort(struct u8500_i2c_regs *i2c_regs) -{ -#ifdef DEBUG - print_abort_reason(i2c_regs); -#endif - /* flush RX and TX fifos */ - flush_fifo(i2c_regs); - - /* Acknowledge the Master Transaction Done */ - i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); - - /* Acknowledge the Master Transaction Done Without Stop */ - i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); - - i2c_init(i2c_bus_speed[i2c_bus_num], CONFIG_SYS_I2C_SLAVE); -} - -/* - * write addr, alias index, to I2C bus. - */ -static int i2c_write_addr(struct u8500_i2c_regs *i2c_regs, uint addr, int alen) -{ - while (alen--) { - /* Wait until the Tx Fifo is not full */ - if (loop_till_bit_clear((void *)&i2c_regs->risr, - U8500_I2C_INT_TXFF, - U8500_I2C_ENDAD_COUNTER)) { - i2c_abort(i2c_regs); - return -1; - } - - /* MSB first */ - writeb((addr >> (alen * 8)) & 0xff, &i2c_regs->tfr); - } - - return 0; -} - -/* - * Internal simplified read function: - * i2c_regs: Pointer to I2C registers for current bus - * chip: I2C chip address, range 0..127 - * addr: Memory (register) address within the chip - * alen: Number of bytes to use for addr (typically 1, 2 for larger - * memories, 0 for register type devices with only one register) - * value: Where to put the data - * - * Returns: 0 on success, not 0 on failure - */ -static int i2c_read_byte(struct u8500_i2c_regs *i2c_regs, uchar chip, - uint addr, int alen, uchar *value) -{ - u32 mcr = 0; - - /* Set the address mode to 7 bit */ - WRITE_FIELD(mcr, U8500_I2C_MCR_AM, U8500_I2C_MCR_SHIFT_AM, 1); - - /* Store the slave address in the master control register */ - WRITE_FIELD(mcr, U8500_I2C_MCR_A7, U8500_I2C_MCR_SHIFT_A7, chip); - - if (alen != 0) { - /* Master write operation */ - mcr &= ~(U8500_I2C_MCR_OP); - - /* Configure the Frame length to one byte */ - WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, - U8500_I2C_MCR_SHIFT_LENGTH, 1); - - /* Repeated start, no stop */ - mcr &= ~(U8500_I2C_MCR_STOP); - - /* Write Master Control Register */ - writel(mcr, &i2c_regs->mcr); - - /* send addr/index */ - if (i2c_write_addr(i2c_regs, addr, alen) != 0) - return -1; - - /* Check for the Master Transaction Done Without Stop */ - if (loop_till_bit_set((void *)&i2c_regs->risr, - U8500_I2C_INT_MTDWS, - U8500_I2C_ENDAD_COUNTER)) { - return -1; - } - - /* Acknowledge the Master Transaction Done Without Stop */ - i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); - } - - /* Master control configuration for read operation */ - mcr |= U8500_I2C_MCR_OP; - - /* Configure the STOP condition, we read only one byte */ - mcr |= U8500_I2C_MCR_STOP; - - /* Set the frame length to one byte, we support only 1 byte reads */ - WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, U8500_I2C_MCR_SHIFT_LENGTH, 1); - - i2c_write_field(&i2c_regs->mcr, U8500_I2C_MCR_LENGTH_STOP_OP, - U8500_I2C_MCR_SHIFT_LENGTH_STOP_OP, mcr); - - /* - * receive_data_polling - */ - - /* Wait until the Rx FIFO is not empty */ - if (loop_till_bit_clear((void *)&i2c_regs->risr, - U8500_I2C_INT_RXFE, - U8500_I2C_ENDAD_COUNTER)) - return -1; - - /* Read the data byte from Rx FIFO */ - *value = readb(&i2c_regs->rfr); - - /* Wait until the work is done */ - if (loop_till_bit_set((void *)&i2c_regs->risr, U8500_I2C_INT_MTD, - U8500_I2C_ENDAD_COUNTER)) - return -1; - - /* Acknowledge the Master Transaction Done */ - i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); - - /* If MTD is set, Master Transaction Done Without Stop is set too */ - i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); - - return 0; -} - -/* - * Internal simplified write function: - * i2c_regs: Pointer to I2C registers for current bus - * chip: I2C chip address, range 0..127 - * addr: Memory (register) address within the chip - * alen: Number of bytes to use for addr (typically 1, 2 for larger - * memories, 0 for register type devices with only one register) - * data: Where to read the data - * len: How many bytes to write - * - * Returns: 0 on success, not 0 on failure - */ -static int __i2c_write(struct u8500_i2c_regs *i2c_regs, u8 chip, uint addr, - int alen, u8 *data, int len) -{ - int i; - u32 mcr = 0; - - /* Set the address mode to 7 bit */ - WRITE_FIELD(mcr, U8500_I2C_MCR_AM, U8500_I2C_MCR_SHIFT_AM, 1); - - /* Store the slave address in the master control register */ - WRITE_FIELD(mcr, U8500_I2C_MCR_A7, U8500_I2C_MCR_SHIFT_A7, chip); - - /* Write operation */ - mcr &= ~(U8500_I2C_MCR_OP); - - /* Current transaction is terminated by STOP condition */ - mcr |= U8500_I2C_MCR_STOP; - - /* Frame length: addr byte + len */ - WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, U8500_I2C_MCR_SHIFT_LENGTH, - (alen + len)); - - /* Write MCR register */ - writel(mcr, &i2c_regs->mcr); - - if (i2c_write_addr(i2c_regs, addr, alen) != 0) - return -1; - - for (i = 0; i < len; i++) { - /* Wait until the Tx FIFO is not full */ - if (loop_till_bit_clear((void *)&i2c_regs->risr, - U8500_I2C_INT_TXFF, - U8500_I2C_ENDAD_COUNTER)) - return -1; - - /* it is a 32 bit register with upper 24 reserved R/O */ - writeb(data[i], &i2c_regs->tfr); - } - - /* Check for Master Transaction Done */ - if (loop_till_bit_set((void *)&i2c_regs->risr, - U8500_I2C_INT_MTD, - U8500_I2C_ENDAD_COUNTER)) { - printf("i2c_write_byte error2: risr %08x\n", - i2c_regs->risr); - return -1; - } - - /* Acknowledge Master Transaction Done */ - i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); - - /* Acknowledge Master Transaction Done Without Stop */ - i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); - - return 0; -} - -/* - * Probe the given I2C chip address. Returns 0 if a chip responded, - * not 0 on failure. - */ -int i2c_probe(uchar chip) -{ - u32 mcr = 0; - struct u8500_i2c_regs *i2c_regs; - - if (chip == CONFIG_SYS_I2C_SLAVE) - return 1; - - i2c_regs = i2c_dev[i2c_bus_num]; - - /* Set the address mode to 7 bit */ - WRITE_FIELD(mcr, U8500_I2C_MCR_AM, U8500_I2C_MCR_SHIFT_AM, 1); - - /* Store the slave address in the master control register */ - WRITE_FIELD(mcr, U8500_I2C_MCR_A10, U8500_I2C_MCR_SHIFT_A7, chip); - - /* Read operation */ - mcr |= U8500_I2C_MCR_OP; - - /* Set the frame length to one byte */ - WRITE_FIELD(mcr, U8500_I2C_MCR_LENGTH, U8500_I2C_MCR_SHIFT_LENGTH, 1); - - /* Current transaction is terminated by STOP condition */ - mcr |= U8500_I2C_MCR_STOP; - - /* Write MCR register */ - writel(mcr, &i2c_regs->mcr); - - /* Wait until the Rx Fifo is not empty */ - if (loop_till_bit_clear((void *)&i2c_regs->risr, - U8500_I2C_INT_RXFE, - U8500_I2C_ENDAD_COUNTER)) { - i2c_abort(i2c_regs); - return -1; - } - - flush_fifo(i2c_regs); - - /* Acknowledge the Master Transaction Done */ - i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTD); - - /* Acknowledge the Master Transaction Done Without Stop */ - i2c_set_bit(&i2c_regs->icr, U8500_I2C_INT_MTDWS); - - return 0; -} - -/* - * Read/Write interface: - * chip: I2C chip address, range 0..127 - * addr: Memory (register) address within the chip - * alen: Number of bytes to use for addr (typically 1, 2 for larger - * memories, 0 for register type devices with only one - * register) - * buffer: Where to read/write the data - * len: How many bytes to read/write - * - * Returns: 0 on success, not 0 on failure - */ -int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) -{ - int i; - int rc; - struct u8500_i2c_regs *i2c_regs; - - if (alen > 2) { - debug("I2C read: addr len %d not supported\n", alen); - return 1; - } - - i2c_regs = i2c_dev[i2c_bus_num]; - - for (i = 0; i < len; i++) { - rc = i2c_read_byte(i2c_regs, chip, addr + i, alen, &buffer[i]); - if (rc != 0) { - debug("I2C read: I/O error: %d\n", rc); - i2c_abort(i2c_regs); - return rc; - } - } - - return 0; -} - -int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) -{ - int rc; - struct u8500_i2c_regs *i2c_regs; - i2c_regs = i2c_dev[i2c_bus_num]; - - rc = __i2c_write(i2c_regs, chip, addr, alen, buffer, - len); - if (rc != 0) { - debug("I2C write: I/O error\n"); - i2c_abort(i2c_regs); - return rc; - } - return 0; -} - -int i2c_set_bus_num(unsigned int bus) -{ - if (bus > ARRAY_SIZE(i2c_dev) - 1) { - debug("i2c_set_bus_num: only up to bus %d supported\n", - ARRAY_SIZE(i2c_dev)-1); - return -1; - } - - i2c_bus_num = bus; - - if (!bus_initialized[i2c_bus_num]) - i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); - - return 0; -} - -int i2c_set_bus_speed(unsigned int speed) -{ - - if (speed > U8500_I2C_MAX_STANDARD_SCL) { - debug("i2c_set_bus_speed: only up to %d supported\n", - U8500_I2C_MAX_STANDARD_SCL); - return -1; - } - - /* sets as side effect i2c_bus_speed[i2c_bus_num] */ - i2c_init(speed, CONFIG_SYS_I2C_SLAVE); - - return 0; -} - -unsigned int i2c_get_bus_num(void) -{ - return i2c_bus_num; -} - -unsigned int i2c_get_bus_speed(void) -{ - return i2c_bus_speed[i2c_bus_num]; -} diff --git a/drivers/i2c/u8500_i2c.h b/drivers/i2c/u8500_i2c.h deleted file mode 100644 index ceecdeede0..0000000000 --- a/drivers/i2c/u8500_i2c.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2009 - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef _U8500_I2C_H_ -#define _U8500_I2C_H_ - -#include <asm/types.h> -#include <asm/io.h> -#include <asm/errno.h> -#include <asm/arch/u8500.h> - -struct u8500_i2c_regs { - u32 cr; /* Control Register 0x00 */ - u32 scr; /* Slave Address Register 0x04 */ - u32 hsmcr; /* HS Master code Register 0x08 */ - u32 mcr; /* Master Control Register 0x0C */ - u32 tfr; /* Transmit Fifo Register 0x10 */ - u32 sr; /* Status Register 0x14 */ - u32 rfr; /* Receiver Fifo Register 0x18 */ - u32 tftr; /* Transmit Fifo Threshold Register 0x1C */ - u32 rftr; /* Receiver Fifo Threshold Register 0x20 */ - u32 dmar; /* DMA register 0x24 */ - u32 brcr; /* Baud Rate Counter Register 0x28 */ - u32 imscr; /* Interrupt Mask Set and Clear Register 0x2C */ - u32 risr; /* Raw interrupt status register 0x30 */ - u32 misr; /* Masked interrupt status register 0x34 */ - u32 icr; /* Interrupt Set and Clear Register 0x38 */ - u32 reserved_1[(0xFE0 - 0x3c) >> 2]; /* Reserved 0x03C to 0xFE0 */ - u32 periph_id_0; /* peripheral ID 0 0xFE0 */ - u32 periph_id_1; /* peripheral ID 1 0xFE4 */ - u32 periph_id_2; /* peripheral ID 2 0xFE8 */ - u32 periph_id_3; /* peripheral ID 3 0xFEC */ - u32 cell_id_0; /* I2C cell ID 0 0xFF0 */ - u32 cell_id_1; /* I2C cell ID 1 0xFF4 */ - u32 cell_id_2; /* I2C cell ID 2 0xFF8 */ - u32 cell_id_3; /* I2C cell ID 3 0xFFC */ -}; - - -/* Control Register */ - -/* Mask values for control register mask */ -#define U8500_I2C_CR_PE 0x0001 /* Peripheral enable */ -#define U8500_I2C_CR_OM 0x0006 /* Operation mode */ -#define U8500_I2C_CR_SAM 0x0008 /* Slave Addressing mode */ -#define U8500_I2C_CR_SM 0x0030 /* Speed mode */ -#define U8500_I2C_CR_SGCM 0x0040 /* Slave General call mode */ -#define U8500_I2C_CR_FTX 0x0080 /* Flush Transmit */ -#define U8500_I2C_CR_FRX 0x0100 /* Flush Receive */ -#define U8500_I2C_CR_DMA_TX_EN 0x0200 /* DMA TX Enable */ -#define U8500_I2C_CR_DMA_RX_EN 0x0400 /* DMA Rx Enable */ -#define U8500_I2C_CR_DMA_SLE 0x0800 /* DMA Synchronization Logic enable */ -#define U8500_I2C_CR_LM 0x1000 /* Loop back mode */ -#define U8500_I2C_CR_FON 0x6000 /* Filtering On */ - -/* shift valus for control register bit fields */ -#define U8500_I2C_CR_SHIFT_PE 0 /* Peripheral enable */ -#define U8500_I2C_CR_SHIFT_OM 1 /* Operation mode */ -#define U8500_I2C_CR_SHIFT_SAM 3 /* Slave Addressing mode */ -#define U8500_I2C_CR_SHIFT_SM 4 /* Speed mode */ -#define U8500_I2C_CR_SHIFT_SGCM 6 /* Slave General call mode */ -#define U8500_I2C_CR_SHIFT_FTX 7 /* Flush Transmit */ -#define U8500_I2C_CR_SHIFT_FRX 8 /* Flush Receive */ -#define U8500_I2C_CR_SHIFT_DMA_TX_EN 9 /* DMA TX Enable */ -#define U8500_I2C_CR_SHIFT_DMA_RX_EN 10 /* DMA Rx Enable */ -#define U8500_I2C_CR_SHIFT_DMA_SLE 11 /* DMA Synch Logic enable */ -#define U8500_I2C_CR_SHIFT_LM 12 /* Loop back mode */ -#define U8500_I2C_CR_SHIFT_FON 13 /* Filtering On */ - -/* bus operation modes */ -#define U8500_I2C_BUS_SLAVE_MODE 0 -#define U8500_I2C_BUS_MASTER_MODE 1 -#define U8500_I2C_BUS_MASTER_SLAVE_MODE 2 - - -/* Slave control register*/ - -/* Mask values slave control register */ -#define U8500_I2C_SCR_ADDR 0x3FF -#define U8500_I2C_SCR_DATA_SETUP_TIME 0xFFFF0000 - -/* Shift values for Slave control register */ -#define U8500_I2C_SCR_SHIFT_ADDR 0 -#define U8500_I2C_SCR_SHIFT_DATA_SETUP_TIME 16 - - -/* Master Control Register */ - -/* Mask values for Master control register */ -#define U8500_I2C_MCR_OP 0x00000001 /* Operation */ -#define U8500_I2C_MCR_A7 0x000000FE /* LSB bits of Address */ -#define U8500_I2C_MCR_EA10 0x00000700 /* Extended Address */ -#define U8500_I2C_MCR_SB 0x00000800 /* Start byte procedure */ -#define U8500_I2C_MCR_AM 0x00003000 /* Address type */ -#define U8500_I2C_MCR_STOP 0x00004000 /* stop condition */ -#define U8500_I2C_MCR_LENGTH 0x03FF8000 /* Frame length */ -#define U8500_I2C_MCR_A10 0x000007FE /* Enable 10 bit address */ -/* mask for length field,stop and operation */ -#define U8500_I2C_MCR_LENGTH_STOP_OP 0x3FFC001 - -/* Shift values for Master control values */ -#define U8500_I2C_MCR_SHIFT_OP 0 /* Operation */ -#define U8500_I2C_MCR_SHIFT_A7 1 /* LSB bits of Address */ -#define U8500_I2C_MCR_SHIFT_EA10 8 /* Extended Address */ -#define U8500_I2C_MCR_SHIFT_SB 11 /* Start byte procedure */ -#define U8500_I2C_MCR_SHIFT_AM 12 /* Address type */ -#define U8500_I2C_MCR_SHIFT_STOP 14 /* stop condition */ -#define U8500_I2C_MCR_SHIFT_LENGTH 15 /* Frame length */ -#define U8500_I2C_MCR_SHIFT_A10 1 /* Enable 10 bit address */ - -#define U8500_I2C_MCR_SHIFT_LENGTH_STOP_OP 0 - - -/* Status Register */ - -/* Mask values for Status register */ -#define U8500_I2C_SR_OP 0x00000003 /* Operation */ -#define U8500_I2C_SR_STATUS 0x0000000C /* Controller Status */ -#define U8500_I2C_SR_CAUSE 0x00000070 /* Abort Cause */ -#define U8500_I2C_SR_TYPE 0x00000180 /* Receive Type */ -#define U8500_I2C_SR_LENGTH 0x000FF700 /* Transfer length */ - -/* Shift values for Status register */ -#define U8500_I2C_SR_SHIFT_OP 0 /* Operation */ -#define U8500_I2C_SR_SHIFT_STATUS 2 /* Controller Status */ -#define U8500_I2C_SR_SHIFT_CAUSE 4 /* Abort Cause */ -#define U8500_I2C_SR_SHIFT_TYPE 7 /* Receive Type */ -#define U8500_I2C_SR_SHIFT_LENGTH 9 /* Transfer length */ - -/* abort cause */ -#define U8500_I2C_NACK_ADDR 0 -#define U8500_I2C_NACK_DATA 1 -#define U8500_I2C_ACK_MCODE 2 -#define U8500_I2C_ARB_LOST 3 -#define U8500_I2C_BERR_START 4 -#define U8500_I2C_BERR_STOP 5 -#define U8500_I2C_OVFL 6 - - -/* Baud rate counter registers */ - -/* Mask values for Baud rate counter register */ -#define U8500_I2C_BRCR_BRCNT2 0xFFFF /* Baud Rate Cntr BRCR for HS */ -#define U8500_I2C_BRCR_BRCNT1 0xFFFF0000 /* BRCR for Standard and Fast */ - -/* Shift values for the Baud rate counter register */ -#define U8500_I2C_BRCR_SHIFT_BRCNT2 0 -#define U8500_I2C_BRCR_SHIFT_BRCNT1 16 - - -/* Interrupt Register */ - -/* Mask values for Interrupt registers */ -#define U8500_I2C_INT_TXFE 0x00000001 /* Tx fifo empty */ -#define U8500_I2C_INT_TXFNE 0x00000002 /* Tx Fifo nearly empty */ -#define U8500_I2C_INT_TXFF 0x00000004 /* Tx Fifo Full */ -#define U8500_I2C_INT_TXFOVR 0x00000008 /* Tx Fifo over run */ -#define U8500_I2C_INT_RXFE 0x00000010 /* Rx Fifo Empty */ -#define U8500_I2C_INT_RXFNF 0x00000020 /* Rx Fifo nearly empty */ -#define U8500_I2C_INT_RXFF 0x00000040 /* Rx Fifo Full */ -#define U8500_I2C_INT_RFSR 0x00010000 /* Read From slave request */ -#define U8500_I2C_INT_RFSE 0x00020000 /* Read from slave empty */ -#define U8500_I2C_INT_WTSR 0x00040000 /* Write to Slave request */ -#define U8500_I2C_INT_MTD 0x00080000 /* Master Transcation Done*/ -#define U8500_I2C_INT_STD 0x00100000 /* Slave Transaction Done */ -#define U8500_I2C_INT_MAL 0x01000000 /* Master Arbitation Lost */ -#define U8500_I2C_INT_BERR 0x02000000 /* Bus Error */ -#define U8500_I2C_INT_MTDWS 0x10000000 /* Master Tran Done wo/ Stop */ - -/* Max clocks (Hz) */ -#define U8500_I2C_MAX_STANDARD_SCL 100000 -#define U8500_I2C_MAX_FAST_SCL 400000 -#define U8500_I2C_MAX_HIGH_SPEED_SCL 3400000 - -#endif /* _U8500_I2C_H_ */ diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index f29a169774..8b38a84de6 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -59,7 +59,7 @@ config CROS_EC_SPI provides a faster and more robust interface than I2C but the bugs are less interesting. -config CONFIG_FSL_SEC_MON +config FSL_SEC_MON bool "Enable FSL SEC_MON Driver" help Freescale Security Monitor block is responsible for monitoring diff --git a/drivers/misc/reset_sandbox.c b/drivers/misc/reset_sandbox.c index 917121bc5e..2691bb031a 100644 --- a/drivers/misc/reset_sandbox.c +++ b/drivers/misc/reset_sandbox.c @@ -40,7 +40,7 @@ static int sandbox_reset_request(struct udevice *dev, enum reset_t type) * (see the U_BOOT_DEVICE() declaration below) should not do anything. * If we are that device, return an error. */ - if (gd->fdt_blob && dev->of_offset == -1) + if (state->fdt_fname && dev->of_offset == -1) return -ENODEV; switch (type) { diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index 1117fedefe..26d34ae5cc 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -10,6 +10,7 @@ #include <common.h> #include <errno.h> #include <malloc.h> +#include <memalign.h> #include <mmc.h> #include <dwmmc.h> #include <asm-generic/errno.h> @@ -213,7 +214,7 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, if (data) { start = get_timer(0); - timeout = 1000; + timeout = 240000; for (;;) { mask = dwmci_readl(host, DWMCI_RINTSTS); /* Error during data transfer. */ diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 371c1ec212..2a58702848 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -16,6 +16,7 @@ #include <mmc.h> #include <part.h> #include <malloc.h> +#include <memalign.h> #include <linux/list.h> #include <div64.h> #include "mmc_private.h" diff --git a/drivers/mmc/rpmb.c b/drivers/mmc/rpmb.c index 9d0b8bc0c8..1c6888fc48 100644 --- a/drivers/mmc/rpmb.c +++ b/drivers/mmc/rpmb.c @@ -10,6 +10,7 @@ #include <config.h> #include <common.h> +#include <memalign.h> #include <mmc.h> #include <u-boot/sha256.h> #include "mmc_private.h" diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 25f18adb67..e717c44216 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -120,17 +120,27 @@ static int mmc_set_mod_clk(struct sunxi_mmc_host *mmchost, unsigned int hz) /* determine delays */ if (hz <= 400000) { oclk_dly = 0; - sclk_dly = 7; + sclk_dly = 0; } else if (hz <= 25000000) { oclk_dly = 0; sclk_dly = 5; +#ifdef CONFIG_MACH_SUN9I } else if (hz <= 50000000) { - oclk_dly = 3; - sclk_dly = 5; + oclk_dly = 5; + sclk_dly = 4; } else { /* hz > 50000000 */ oclk_dly = 2; sclk_dly = 4; +#else + } else if (hz <= 50000000) { + oclk_dly = 3; + sclk_dly = 4; + } else { + /* hz > 50000000 */ + oclk_dly = 1; + sclk_dly = 4; +#endif } writel(CCM_MMC_CTRL_ENABLE | pll | CCM_MMC_CTRL_SCLK_DLY(sclk_dly) | diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 71c1a519e9..b4e5376176 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -60,7 +60,6 @@ obj-$(CONFIG_NAND_VF610_NFC) += vf610_nfc.o obj-$(CONFIG_NAND_MXC) += mxc_nand.o obj-$(CONFIG_NAND_MXS) += mxs_nand.o obj-$(CONFIG_NAND_NDFC) += ndfc.o -obj-$(CONFIG_NAND_NOMADIK) += nomadik.o obj-$(CONFIG_NAND_PXA3XX) += pxa3xx_nand.o obj-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o obj-$(CONFIG_NAND_SPEAR) += spr_nand.o diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 567eff0914..e0e9e1ebd0 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -390,6 +390,55 @@ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, return 0; } +#ifndef CONFIG_SPL_BUILD +/* + * fsmc_nand_switch_ecc - switch the ECC operation between different engines + * + * @eccstrength - the number of bits that could be corrected + * (1 - HW, 4 - SW BCH4) + */ +int fsmc_nand_switch_ecc(uint32_t eccstrength) +{ + struct nand_chip *nand; + struct mtd_info *mtd; + int err; + + /* + * This functions is only called on SPEAr600 platforms, supporting + * 1 bit HW ECC. The BCH8 HW ECC (FSMC_VER8) from the ST-Ericsson + * Nomadik SoC is currently supporting this fsmc_nand_switch_ecc() + * function, as it doesn't need to switch to a different ECC layout. + */ + mtd = &nand_info[nand_curr_device]; + nand = mtd->priv; + + /* Setup the ecc configurations again */ + if (eccstrength == 1) { + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.bytes = 3; + nand->ecc.strength = 1; + nand->ecc.layout = &fsmc_ecc1_layout; + nand->ecc.calculate = fsmc_read_hwecc; + nand->ecc.correct = nand_correct_data; + } else if (eccstrength == 4) { + /* + * .calculate .correct and .bytes will be set in + * nand_scan_tail() + */ + nand->ecc.mode = NAND_ECC_SOFT_BCH; + nand->ecc.strength = 4; + nand->ecc.layout = NULL; + } else { + printf("Error: ECC strength %d not supported!\n", eccstrength); + } + + /* Update NAND handling after ECC mode switch */ + err = nand_scan_tail(mtd); + + return err; +} +#endif /* CONFIG_SPL_BUILD */ + int fsmc_nand_init(struct nand_chip *nand) { static int chip_nr; diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 7a62cc3361..abcedc2102 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -16,7 +16,6 @@ #define JZ_NAND_CMD_ADDR (JZ_NAND_DATA_ADDR + 0x8000) #define JZ_NAND_ADDR_ADDR (JZ_NAND_DATA_ADDR + 0x10000) -#define BIT(x) (1 << (x)) #define JZ_NAND_ECC_CTRL_ENCODING BIT(3) #define JZ_NAND_ECC_CTRL_RS BIT(2) #define JZ_NAND_ECC_CTRL_RESET BIT(1) diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c index 1d689015a5..f15cf36c88 100644 --- a/drivers/mtd/nand/mxs_nand.c +++ b/drivers/mtd/nand/mxs_nand.c @@ -149,6 +149,13 @@ static inline uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size, uint32_t page_oob_size) { int ecc_strength; + int max_ecc_strength_supported; + + /* Refer to Chapter 17 for i.MX6DQ, Chapter 18 for i.MX6SX */ + if (is_cpu_type(MXC_CPU_MX6SX)) + max_ecc_strength_supported = 62; + else + max_ecc_strength_supported = 40; /* * Determine the ECC layout with the formula: @@ -162,7 +169,7 @@ static inline uint32_t mxs_nand_get_ecc_strength(uint32_t page_data_size, / (galois_field * mxs_nand_ecc_chunk_cnt(page_data_size)); - return round_down(ecc_strength, 2); + return min(round_down(ecc_strength, 2), max_ecc_strength_supported); } static inline uint32_t mxs_nand_get_mark_offset(uint32_t page_data_size, diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 21b4a618ce..71285b6669 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -23,6 +23,7 @@ #include <command.h> #include <watchdog.h> #include <malloc.h> +#include <memalign.h> #include <div64.h> #include <asm/errno.h> diff --git a/drivers/mtd/nand/nomadik.c b/drivers/mtd/nand/nomadik.c deleted file mode 100644 index a7cee5138d..0000000000 --- a/drivers/mtd/nand/nomadik.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * (C) Copyright 2007 STMicroelectronics, <www.st.com> - * (C) Copyright 2009 Alessandro Rubini <rubini@unipv.it> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <nand.h> -#include <asm/io.h> - -static inline int parity(int b) /* b is really a byte; returns 0 or ~0 */ -{ - __asm__ __volatile__( - "eor %0, %0, %0, lsr #4\n\t" - "eor %0, %0, %0, lsr #2\n\t" - "eor %0, %0, %0, lsr #1\n\t" - "ands %0, %0, #1\n\t" - "subne %0, %0, #2\t" - : "=r" (b) : "0" (b)); - return b; -} - -/* - * This is the ECC routine used in hardware, according to the manual. - * HW claims to make the calculation but not the correction; so we must - * recalculate the bytes for a comparison. - */ -static int ecc512(const unsigned char *data, unsigned char *ecc) -{ - int gpar = 0; - int i, val, par; - int pbits = 0; /* P8, P16, ... P2048 */ - int pprime = 0; /* P8', P16', ... P2048' */ - int lowbits; /* P1, P2, P4 and primes */ - - for (i = 0; i < 512; i++) { - par = parity((val = data[i])); - gpar ^= val; - pbits ^= (i & par); - } - /* - * Ok, now gpar is global parity (xor of all bytes) - * pbits are all the parity bits (non-prime ones) - */ - par = parity(gpar); - pprime = pbits ^ par; - /* Put low bits in the right position for ecc[2] (bits 7..2) */ - lowbits = 0 - | (parity(gpar & 0xf0) & 0x80) /* P4 */ - | (parity(gpar & 0x0f) & 0x40) /* P4' */ - | (parity(gpar & 0xcc) & 0x20) /* P2 */ - | (parity(gpar & 0x33) & 0x10) /* P2' */ - | (parity(gpar & 0xaa) & 0x08) /* P1 */ - | (parity(gpar & 0x55) & 0x04); /* P1' */ - - ecc[2] = ~(lowbits | ((pbits & 0x100) >> 7) | ((pprime & 0x100) >> 8)); - /* now intermix bits for ecc[1] (P1024..P128') and ecc[0] (P64..P8') */ - ecc[1] = ~( (pbits & 0x80) >> 0 | ((pprime & 0x80) >> 1) - | ((pbits & 0x40) >> 1) | ((pprime & 0x40) >> 2) - | ((pbits & 0x20) >> 2) | ((pprime & 0x20) >> 3) - | ((pbits & 0x10) >> 3) | ((pprime & 0x10) >> 4)); - - ecc[0] = ~( (pbits & 0x8) << 4 | ((pprime & 0x8) << 3) - | ((pbits & 0x4) << 3) | ((pprime & 0x4) << 2) - | ((pbits & 0x2) << 2) | ((pprime & 0x2) << 1) - | ((pbits & 0x1) << 1) | ((pprime & 0x1) << 0)); - return 0; -} - -/* This is the method in the chip->ecc field */ -static int nomadik_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat, - uint8_t *ecc_code) -{ - return ecc512(dat, ecc_code); -} - -static int nomadik_ecc_correct(struct mtd_info *mtd, uint8_t *dat, - uint8_t *r_ecc, uint8_t *c_ecc) -{ - struct nand_chip *chip = mtd->priv; - uint32_t r, c, d, diff; /*read, calculated, xor of them */ - - if (!memcmp(r_ecc, c_ecc, chip->ecc.bytes)) - return 0; - - /* Reorder the bytes into ascending-order 24 bits -- see manual */ - r = r_ecc[2] << 22 | r_ecc[1] << 14 | r_ecc[0] << 6 | r_ecc[2] >> 2; - c = c_ecc[2] << 22 | c_ecc[1] << 14 | c_ecc[0] << 6 | c_ecc[2] >> 2; - diff = (r ^ c) & ((1<<24)-1); /* use 24 bits only */ - - /* If 12 bits are different, one per pair, it's correctable */ - if (((diff | (diff>>1)) & 0x555555) == 0x555555) { - int bit = ((diff & 2) >> 1) - | ((diff & 0x8) >> 2) | ((diff & 0x20) >> 3); - int byte; - - d = diff >> 6; /* remove bit-order info */ - byte = ((d & 2) >> 1) - | ((d & 0x8) >> 2) | ((d & 0x20) >> 3) - | ((d & 0x80) >> 4) | ((d & 0x200) >> 5) - | ((d & 0x800) >> 6) | ((d & 0x2000) >> 7) - | ((d & 0x8000) >> 8) | ((d & 0x20000) >> 9); - /* correct the single bit */ - dat[byte] ^= 1<<bit; - return 0; - } - /* If 1 bit only differs, it's one bit error in ECC, ignore */ - if ((diff ^ (1 << (ffs(diff) - 1))) == 0) - return 0; - /* Otherwise, uncorrectable */ - return -1; -} - -static void nomadik_ecc_hwctl(struct mtd_info *mtd, int mode) -{ /* mandatory in the structure but not used here */ } - - -/* This is the layout used by older installations, we keep compatible */ -struct nand_ecclayout nomadik_ecc_layout = { - .eccbytes = 3 * 4, - .eccpos = { /* each subpage has 16 bytes: pos 2,3,4 hosts ECC */ - 0x02, 0x03, 0x04, - 0x12, 0x13, 0x14, - 0x22, 0x23, 0x24, - 0x32, 0x33, 0x34}, - .oobfree = { {0x08, 0x08}, {0x18, 0x08}, {0x28, 0x08}, {0x38, 0x08} }, -}; - -#define MASK_ALE (1 << 24) /* our ALE is AD21 */ -#define MASK_CLE (1 << 23) /* our CLE is AD22 */ - -/* This is copied from the AT91SAM9 devices (Stelian Pop, Lead Tech Design) */ -static void nomadik_nand_hwcontrol(struct mtd_info *mtd, - int cmd, unsigned int ctrl) -{ - struct nand_chip *this = mtd->priv; - u32 pcr0 = readl(REG_FSMC_PCR0); - - if (ctrl & NAND_CTRL_CHANGE) { - ulong IO_ADDR_W = (ulong) this->IO_ADDR_W; - IO_ADDR_W &= ~(MASK_ALE | MASK_CLE); - - if (ctrl & NAND_CLE) - IO_ADDR_W |= MASK_CLE; - if (ctrl & NAND_ALE) - IO_ADDR_W |= MASK_ALE; - - if (ctrl & NAND_NCE) - writel(pcr0 | 0x4, REG_FSMC_PCR0); - else - writel(pcr0 & ~0x4, REG_FSMC_PCR0); - - this->IO_ADDR_W = (void *) IO_ADDR_W; - this->IO_ADDR_R = (void *) IO_ADDR_W; - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); -} - -/* Returns 1 when ready; upper layers timeout at 20ms with timer routines */ -static int nomadik_nand_ready(struct mtd_info *mtd) -{ - return 1; /* The ready bit is handled in hardware */ -} - -/* Copy a buffer 32bits at a time: faster than defualt method which is 8bit */ -static void nomadik_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - u32 *p = (u32 *) buf; - - len >>= 2; - writel(0, REG_FSMC_ECCR0); - for (i = 0; i < len; i++) - p[i] = readl(chip->IO_ADDR_R); -} - -int board_nand_init(struct nand_chip *chip) -{ - /* Set up the FSMC_PCR0 for nand access*/ - writel(0x0000004a, REG_FSMC_PCR0); - /* Set up FSMC_PMEM0, FSMC_PATT0 with timing data for access */ - writel(0x00020401, REG_FSMC_PMEM0); - writel(0x00020404, REG_FSMC_PATT0); - - chip->options = NAND_COPYBACK | NAND_CACHEPRG | NAND_NO_PADDING; - chip->cmd_ctrl = nomadik_nand_hwcontrol; - chip->dev_ready = nomadik_nand_ready; - /* The chip allows 32bit reads, so avoid the default 8bit copy */ - chip->read_buf = nomadik_nand_read_buf; - - /* ECC: follow the hardware-defined rulse, but do it in sw */ - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.bytes = 3; - chip->ecc.size = 512; - chip->ecc.strength = 1; - chip->ecc.layout = &nomadik_ecc_layout; - chip->ecc.calculate = nomadik_ecc_calculate; - chip->ecc.hwctl = nomadik_ecc_hwctl; - chip->ecc.correct = nomadik_ecc_correct; - - return 0; -} diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index 4372988ed2..4814fa202a 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -558,10 +558,10 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, bit_pos = error_loc[count] % 8; if (byte_pos < SECTOR_BYTES) { dat[byte_pos] ^= 1 << bit_pos; - printf("nand: bit-flip corrected @data=%d\n", byte_pos); + debug("nand: bit-flip corrected @data=%d\n", byte_pos); } else if (byte_pos < error_max) { read_ecc[byte_pos - SECTOR_BYTES] ^= 1 << bit_pos; - printf("nand: bit-flip corrected @oob=%d\n", byte_pos - + debug("nand: bit-flip corrected @oob=%d\n", byte_pos - SECTOR_BYTES); } else { err = -EBADMSG; @@ -663,7 +663,7 @@ static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data, /* correct data only, not ecc bytes */ if (errloc[i] < 8*512) data[errloc[i]/8] ^= 1 << (errloc[i] & 7); - printf("corrected bitflip %u\n", errloc[i]); + debug("corrected bitflip %u\n", errloc[i]); #ifdef DEBUG puts("read_ecc: "); /* diff --git a/drivers/mtd/nand/sunxi_nand_spl.c b/drivers/mtd/nand/sunxi_nand_spl.c index bf9b1b1450..b0e07aa2d0 100644 --- a/drivers/mtd/nand/sunxi_nand_spl.c +++ b/drivers/mtd/nand/sunxi_nand_spl.c @@ -321,6 +321,7 @@ static int nand_read_buffer(uint32_t offs, unsigned int size, void *dest, { 8192, 40, 1024, 5 }, { 16384, 56, 1024, 5 }, { 8192, 24, 1024, 5 }, + { 4096, 24, 1024, 5 }, }; static int nand_config = -1; int i; @@ -355,18 +356,32 @@ static int nand_read_buffer(uint32_t offs, unsigned int size, void *dest, int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest) { +#if CONFIG_SYS_NAND_U_BOOT_OFFS == CONFIG_SPL_PAD_TO + /* + * u-boot-dtb.bin appended to SPL, use syndrome (like the BROM does) + * and try different erase block sizes to find the backup. + */ const uint32_t boot_offsets[] = { 0 * 1024 * 1024 + CONFIG_SYS_NAND_U_BOOT_OFFS, 1 * 1024 * 1024 + CONFIG_SYS_NAND_U_BOOT_OFFS, 2 * 1024 * 1024 + CONFIG_SYS_NAND_U_BOOT_OFFS, 4 * 1024 * 1024 + CONFIG_SYS_NAND_U_BOOT_OFFS, }; - int i, syndrome; - - if (CONFIG_SYS_NAND_U_BOOT_OFFS == CONFIG_SPL_PAD_TO) - syndrome = 1; /* u-boot-dtb.bin appended to SPL */ - else - syndrome = 0; /* u-boot-dtb.bin on its own partition */ + const int syndrome = 1; +#else + /* + * u-boot-dtb.bin on its own partition, do not use syndrome, u-boot + * partition sits after 2 eraseblocks (spl, spl-backup), look for + * backup u-boot 1 erase block further. + */ + const uint32_t eraseblock_size = CONFIG_SYS_NAND_U_BOOT_OFFS / 2; + const uint32_t boot_offsets[] = { + CONFIG_SYS_NAND_U_BOOT_OFFS, + CONFIG_SYS_NAND_U_BOOT_OFFS + eraseblock_size, + }; + const int syndrome = 0; +#endif + int i; if (offs == CONFIG_SYS_NAND_U_BOOT_OFFS) { for (i = 0; i < ARRAY_SIZE(boot_offsets); i++) { diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c index debad4f791..a77db7b65d 100644 --- a/drivers/mtd/nand/tegra_nand.c +++ b/drivers/mtd/nand/tegra_nand.c @@ -9,6 +9,7 @@ #include <common.h> #include <asm/io.h> +#include <memalign.h> #include <nand.h> #include <asm/arch/clock.h> #include <asm/arch/funcmux.h> diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c index 4a4a3afc92..8f5bdda3d7 100644 --- a/drivers/mtd/spi/sf_params.c +++ b/drivers/mtd/spi/sf_params.c @@ -23,6 +23,7 @@ const struct spi_flash_params spi_flash_params_table[] = { {"AT45DB321D", 0x1f2700, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K}, {"AT45DB641D", 0x1f2800, 0x0, 64 * 1024, 128, RD_NORM, SECT_4K}, {"AT25DF321", 0x1f4701, 0x0, 64 * 1024, 64, RD_NORM, SECT_4K}, + {"AT26DF081A", 0x1f4501, 0x0, 64 * 1024, 16, RD_NORM, SECT_4K}, #endif #ifdef CONFIG_SPI_FLASH_EON /* EON */ {"EN25Q32B", 0x1c3016, 0x0, 64 * 1024, 64, RD_NORM, 0}, diff --git a/drivers/net/designware.c b/drivers/net/designware.c index ae78d21db6..6433896eec 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -14,6 +14,7 @@ #include <errno.h> #include <miiphy.h> #include <malloc.h> +#include <pci.h> #include <linux/compiler.h> #include <linux/err.h> #include <asm/io.h> @@ -558,6 +559,22 @@ static int designware_eth_write_hwaddr(struct udevice *dev) return _dw_write_hwaddr(priv, pdata->enetaddr); } +static int designware_eth_bind(struct udevice *dev) +{ +#ifdef CONFIG_DM_PCI + static int num_cards; + char name[20]; + + /* Create a unique device name for PCI type devices */ + if (device_is_on_pci_bus(dev)) { + sprintf(name, "eth_designware#%u", num_cards++); + device_set_name(dev, name); + } +#endif + + return 0; +} + static int designware_eth_probe(struct udevice *dev) { struct eth_pdata *pdata = dev_get_platdata(dev); @@ -565,6 +582,23 @@ static int designware_eth_probe(struct udevice *dev) u32 iobase = pdata->iobase; int ret; +#ifdef CONFIG_DM_PCI + /* + * If we are on PCI bus, either directly attached to a PCI root port, + * or via a PCI bridge, fill in platdata before we probe the hardware. + */ + if (device_is_on_pci_bus(dev)) { + pci_dev_t bdf = pci_get_bdf(dev); + + dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &iobase); + iobase &= PCI_BASE_ADDRESS_MEM_MASK; + iobase = pci_mem_to_phys(bdf, iobase); + + pdata->iobase = iobase; + pdata->phy_interface = PHY_INTERFACE_MODE_RMII; + } +#endif + debug("%s, iobase=%x, priv=%p\n", __func__, iobase, priv); priv->mac_regs_p = (struct eth_mac_regs *)iobase; priv->dma_regs_p = (struct eth_dma_regs *)(iobase + DW_DMA_BASE_OFFSET); @@ -617,10 +651,18 @@ U_BOOT_DRIVER(eth_designware) = { .id = UCLASS_ETH, .of_match = designware_eth_ids, .ofdata_to_platdata = designware_eth_ofdata_to_platdata, + .bind = designware_eth_bind, .probe = designware_eth_probe, .ops = &designware_eth_ops, .priv_auto_alloc_size = sizeof(struct dw_eth_dev), .platdata_auto_alloc_size = sizeof(struct eth_pdata), .flags = DM_FLAG_ALLOC_PRIV_DMA, }; + +static struct pci_device_id supported[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_EMAC) }, + { } +}; + +U_BOOT_PCI_DEVICE(eth_designware, supported); #endif diff --git a/drivers/net/e1000.c b/drivers/net/e1000.c index 7b830ff8c0..2ba03ed73e 100644 --- a/drivers/net/e1000.c +++ b/drivers/net/e1000.c @@ -32,6 +32,7 @@ tested on both gig copper and gig fiber boards #include <common.h> #include <dm.h> #include <errno.h> +#include <memalign.h> #include <pci.h> #include "e1000.h" diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index bff5fd1119..79f6737e8e 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -10,6 +10,7 @@ #include <common.h> #include <malloc.h> +#include <memalign.h> #include <net.h> #include <netdev.h> #include <miiphy.h> diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 31042a6b6b..bf972dc39b 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -170,7 +170,11 @@ int nc_input_packet(uchar *pkt, struct in_addr src_ip, unsigned dest_port, static void nc_send_packet(const char *buf, int len) { +#ifdef CONFIG_DM_ETH + struct udevice *eth; +#else struct eth_device *eth; +#endif int inited = 0; uchar *pkt; uchar *ether; @@ -183,7 +187,7 @@ static void nc_send_packet(const char *buf, int len) return; if (!memcmp(nc_ether, net_null_ethaddr, 6)) { - if (eth->state == ETH_STATE_ACTIVE) + if (eth_is_active(eth)) return; /* inside net loop */ output_packet = buf; output_packet_len = len; @@ -194,7 +198,7 @@ static void nc_send_packet(const char *buf, int len) return; } - if (eth->state != ETH_STATE_ACTIVE) { + if (!eth_is_active(eth)) { if (eth_is_on_demand_init()) { if (eth_init() < 0) return; @@ -292,7 +296,11 @@ static int nc_stdio_getc(struct stdio_dev *dev) static int nc_stdio_tstc(struct stdio_dev *dev) { +#ifdef CONFIG_DM_ETH + struct udevice *eth; +#else struct eth_device *eth; +#endif if (input_recursion) return 0; @@ -301,7 +309,7 @@ static int nc_stdio_tstc(struct stdio_dev *dev) return 1; eth = eth_get_dev(); - if (eth && eth->state == ETH_STATE_ACTIVE) + if (eth_is_active(eth)) return 0; /* inside net loop */ input_recursion = 1; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 65c731afb6..a6023f1033 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -571,7 +571,7 @@ static struct phy_device *phy_device_create(struct mii_dev *bus, int addr, memset(dev, 0, sizeof(*dev)); dev->duplex = -1; - dev->link = 1; + dev->link = 0; dev->interface = interface; dev->autoneg = AUTONEG_ENABLE; diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 7b6e20f30f..ebd46b27e5 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -44,6 +44,7 @@ #include <dm.h> #include <errno.h> #include <malloc.h> +#include <memalign.h> #include <net.h> #ifndef CONFIG_DM_ETH #include <netdev.h> diff --git a/drivers/net/smc91111.c b/drivers/net/smc91111.c index ade14cd475..f31216ffa6 100644 --- a/drivers/net/smc91111.c +++ b/drivers/net/smc91111.c @@ -499,15 +499,8 @@ again: } /* we have a packet address, so tell the card to use it */ -#ifndef CONFIG_XAENIAX SMC_outb (dev, packet_no, PN_REG); -#else - /* On Xaeniax board, we can't use SMC_outb here because that way - * the Allocate MMU command will end up written to the command register - * as well, which will lead to a problem. - */ - SMC_outl (dev, packet_no << 16, 0); -#endif + /* do not write new ptr value if Write data fifo not empty */ while ( saved_ptr & PTR_NOTEMPTY ) printf ("Write data fifo not empty!\n"); @@ -542,39 +535,19 @@ again: */ #ifdef USE_32_BIT SMC_outsl (dev, SMC91111_DATA_REG, buf, length >> 2); -#ifndef CONFIG_XAENIAX if (length & 0x2) SMC_outw (dev, *((word *) (buf + (length & 0xFFFFFFFC))), SMC91111_DATA_REG); #else - /* On XANEIAX, we can only use 32-bit writes, so we need to handle - * unaligned tail part specially. The standard code doesn't work. - */ - if ((length & 3) == 3) { - u16 * ptr = (u16*) &buf[length-3]; - SMC_outl(dev, (*ptr) | ((0x2000 | buf[length-1]) << 16), - SMC91111_DATA_REG); - } else if ((length & 2) == 2) { - u16 * ptr = (u16*) &buf[length-2]; - SMC_outl(dev, *ptr, SMC91111_DATA_REG); - } else if (length & 1) { - SMC_outl(dev, (0x2000 | buf[length-1]), SMC91111_DATA_REG); - } else { - SMC_outl(dev, 0, SMC91111_DATA_REG); - } -#endif -#else SMC_outsw (dev, SMC91111_DATA_REG, buf, (length) >> 1); #endif /* USE_32_BIT */ -#ifndef CONFIG_XAENIAX /* Send the last byte, if there is one. */ if ((length & 1) == 0) { SMC_outw (dev, 0, SMC91111_DATA_REG); } else { SMC_outw (dev, buf[length - 1] | 0x2000, SMC91111_DATA_REG); } -#endif /* and let the chipset deal with it */ SMC_outw (dev, MC_ENQUEUE, MMU_CMD_REG); @@ -588,9 +561,6 @@ again: /* release packet */ /* no need to release, MMU does that now */ -#ifdef CONFIG_XAENIAX - SMC_outw (dev, MC_FREEPKT, MMU_CMD_REG); -#endif /* wait for MMU getting ready (low) */ while (SMC_inw (dev, MMU_CMD_REG) & MC_BUSY) { @@ -610,9 +580,6 @@ again: /* release packet */ /* no need to release, MMU does that now */ -#ifdef CONFIG_XAENIAX - SMC_outw (dev, MC_FREEPKT, MMU_CMD_REG); -#endif /* wait for MMU getting ready (low) */ while (SMC_inw (dev, MMU_CMD_REG) & MC_BUSY) { @@ -625,15 +592,7 @@ again: } /* restore previously saved registers */ -#ifndef CONFIG_XAENIAX SMC_outb( dev, saved_pnr, PN_REG ); -#else - /* On Xaeniax board, we can't use SMC_outb here because that way - * the Allocate MMU command will end up written to the command register - * as well, which will lead to a problem. - */ - SMC_outl(dev, saved_pnr << 16, 0); -#endif SMC_outw( dev, saved_ptr, PTR_REG ); return length; @@ -802,15 +761,7 @@ static int smc_rcv(struct eth_device *dev) udelay(1); /* Wait until not busy */ /* restore saved registers */ -#ifndef CONFIG_XAENIAX SMC_outb( dev, saved_pnr, PN_REG ); -#else - /* On Xaeniax board, we can't use SMC_outb here because that way - * the Allocate MMU command will end up written to the command register - * as well, which will lead to a problem. - */ - SMC_outl( dev, saved_pnr << 16, 0); -#endif SMC_outw( dev, saved_ptr, PTR_REG ); if (!is_error) { diff --git a/drivers/net/smc91111.h b/drivers/net/smc91111.h index e19c491cbc..5197f36039 100644 --- a/drivers/net/smc91111.h +++ b/drivers/net/smc91111.h @@ -77,19 +77,6 @@ struct smc91111_priv{ if (__p & 2) __v >>= 8; \ else __v &= 0xff; \ __v; }) -#elif defined(CONFIG_XAENIAX) -#define SMC_inl(a,r) (*((volatile dword *)((a)->iobase+(r)))) -#define SMC_inw(a,z) ({ \ - unsigned int __p = (unsigned int)((a)->iobase + (z)); \ - unsigned int __v = *(volatile unsigned int *)((__p) & ~3); \ - if (__p & 3) __v >>= 16; \ - else __v &= 0xffff; \ - __v; }) -#define SMC_inb(a,p) ({ \ - unsigned int ___v = SMC_inw((a),(p) & ~1); \ - if ((p) & 1) ___v >>= 8; \ - else ___v &= 0xff; \ - ___v; }) #else #define SMC_inl(a,r) (*((volatile dword *)((a)->iobase+(r)))) #define SMC_inw(a,r) (*((volatile word *)((a)->iobase+(r)))) @@ -104,15 +91,6 @@ struct smc91111_priv{ #ifdef CONFIG_XSENGINE #define SMC_outl(a,d,r) (*((volatile dword *)((a)->iobase+(r<<1))) = d) #define SMC_outw(a,d,r) (*((volatile word *)((a)->iobase+(r<<1))) = d) -#elif defined (CONFIG_XAENIAX) -#define SMC_outl(a,d,r) (*((volatile dword *)((a)->iobase+(r))) = d) -#define SMC_outw(a,d,p) ({ \ - dword __dwo = SMC_inl((a),(p) & ~3); \ - dword __dwn = (word)(d); \ - __dwo &= ((p) & 3) ? 0x0000ffff : 0xffff0000; \ - __dwo |= ((p) & 3) ? __dwn << 16 : __dwn; \ - SMC_outl((a), __dwo, (p) & ~3); \ -}) #else #define SMC_outl(a,d,r) (*((volatile dword *)((a)->iobase+(r))) = d) #define SMC_outw(a,d,r) (*((volatile word *)((a)->iobase+(r))) = d) diff --git a/drivers/net/vsc9953.c b/drivers/net/vsc9953.c index fed7358448..7595db1acb 100644 --- a/drivers/net/vsc9953.c +++ b/drivers/net/vsc9953.c @@ -1,5 +1,5 @@ /* - * Copyright 2014 Freescale Semiconductor, Inc. + * Copyright 2014 - 2015 Freescale Semiconductor, Inc. * * SPDX-License-Identifier: GPL-2.0+ * @@ -10,7 +10,11 @@ #include <asm/fsl_serdes.h> #include <fm_eth.h> #include <fsl_memac.h> +#include <bitfield.h> +#include <errno.h> +#include <malloc.h> #include <vsc9953.h> +#include <ethsw.h> static struct vsc9953_info vsc9953_l2sw = { .port[0] = VSC9953_PORT_INFO_INITIALIZER(0), @@ -25,50 +29,50 @@ static struct vsc9953_info vsc9953_l2sw = { .port[9] = VSC9953_PORT_INFO_INITIALIZER(9), }; -void vsc9953_port_info_set_mdio(int port, struct mii_dev *bus) +void vsc9953_port_info_set_mdio(int port_no, struct mii_dev *bus) { - if (!VSC9953_PORT_CHECK(port)) + if (!VSC9953_PORT_CHECK(port_no)) return; - vsc9953_l2sw.port[port].bus = bus; + vsc9953_l2sw.port[port_no].bus = bus; } -void vsc9953_port_info_set_phy_address(int port, int address) +void vsc9953_port_info_set_phy_address(int port_no, int address) { - if (!VSC9953_PORT_CHECK(port)) + if (!VSC9953_PORT_CHECK(port_no)) return; - vsc9953_l2sw.port[port].phyaddr = address; + vsc9953_l2sw.port[port_no].phyaddr = address; } -void vsc9953_port_info_set_phy_int(int port, phy_interface_t phy_int) +void vsc9953_port_info_set_phy_int(int port_no, phy_interface_t phy_int) { - if (!VSC9953_PORT_CHECK(port)) + if (!VSC9953_PORT_CHECK(port_no)) return; - vsc9953_l2sw.port[port].enet_if = phy_int; + vsc9953_l2sw.port[port_no].enet_if = phy_int; } -void vsc9953_port_enable(int port) +void vsc9953_port_enable(int port_no) { - if (!VSC9953_PORT_CHECK(port)) + if (!VSC9953_PORT_CHECK(port_no)) return; - vsc9953_l2sw.port[port].enabled = 1; + vsc9953_l2sw.port[port_no].enabled = 1; } -void vsc9953_port_disable(int port) +void vsc9953_port_disable(int port_no) { - if (!VSC9953_PORT_CHECK(port)) + if (!VSC9953_PORT_CHECK(port_no)) return; - vsc9953_l2sw.port[port].enabled = 0; + vsc9953_l2sw.port[port_no].enabled = 0; } static void vsc9953_mdio_write(struct vsc9953_mii_mng *phyregs, int port_addr, int regnum, int value) { - int timeout = 50000; + int timeout = 50000; out_le32(&phyregs->miimcmd, (0x1 << 31) | ((port_addr & 0x1f) << 25) | ((regnum & 0x1f) << 20) | ((value & 0xffff) << 4) | @@ -85,8 +89,8 @@ static void vsc9953_mdio_write(struct vsc9953_mii_mng *phyregs, int port_addr, static int vsc9953_mdio_read(struct vsc9953_mii_mng *phyregs, int port_addr, int regnum) { - int value = 0xFFFF; - int timeout = 50000; + int value = 0xFFFF; + int timeout = 50000; while ((in_le32(&phyregs->miimstatus) & MIIMIND_OPR_PEND) && --timeout) udelay(1); @@ -120,8 +124,8 @@ static int vsc9953_mdio_read(struct vsc9953_mii_mng *phyregs, int port_addr, static int init_phy(struct eth_device *dev) { - struct vsc9953_port_info *l2sw_port = dev->priv; - struct phy_device *phydev = NULL; + struct vsc9953_port_info *l2sw_port = dev->priv; + struct phy_device *phydev = NULL; #ifdef CONFIG_PHYLIB if (!l2sw_port->bus) @@ -148,21 +152,21 @@ static int init_phy(struct eth_device *dev) return 0; } -static int vsc9953_port_init(int port) +static int vsc9953_port_init(int port_no) { - struct eth_device *dev; + struct eth_device *dev; /* Internal ports never have a PHY */ - if (VSC9953_INTERNAL_PORT_CHECK(port)) + if (VSC9953_INTERNAL_PORT_CHECK(port_no)) return 0; /* alloc eth device */ dev = (struct eth_device *)calloc(1, sizeof(struct eth_device)); if (!dev) - return 1; + return -ENOMEM; - sprintf(dev->name, "SW@PORT%d", port); - dev->priv = &vsc9953_l2sw.port[port]; + sprintf(dev->name, "SW@PORT%d", port_no); + dev->priv = &vsc9953_l2sw.port[port_no]; dev->init = NULL; dev->halt = NULL; dev->send = NULL; @@ -170,225 +174,485 @@ static int vsc9953_port_init(int port) if (init_phy(dev)) { free(dev); - return 1; + return -ENODEV; } return 0; } -void vsc9953_init(bd_t *bis) +static int vsc9953_vlan_table_poll_idle(void) { - u32 i, hdx_cfg = 0, phy_addr = 0; - int timeout; - struct vsc9953_system_reg *l2sys_reg; - struct vsc9953_qsys_reg *l2qsys_reg; - struct vsc9953_dev_gmii *l2dev_gmii_reg; - struct vsc9953_analyzer *l2ana_reg; - struct vsc9953_devcpu_gcb *l2dev_gcb; + struct vsc9953_analyzer *l2ana_reg; + int timeout; - l2dev_gmii_reg = (struct vsc9953_dev_gmii *)(VSC9953_OFFSET + - VSC9953_DEV_GMII_OFFSET); + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + timeout = 50000; + while (((in_le32(&l2ana_reg->ana_tables.vlan_access) & + VSC9953_VLAN_CMD_MASK) != VSC9953_VLAN_CMD_IDLE) && --timeout) + udelay(1); + + return timeout ? 0 : -EBUSY; +} + +#ifdef CONFIG_CMD_ETHSW +/* Add/remove a port to/from a VLAN */ +static void vsc9953_vlan_table_membership_set(int vid, u32 port_no, u8 add) +{ + u32 val; + struct vsc9953_analyzer *l2ana_reg; l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + VSC9953_ANA_OFFSET); - l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET + - VSC9953_SYS_OFFSET); + if (vsc9953_vlan_table_poll_idle() < 0) { + debug("VLAN table timeout\n"); + return; + } - l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET + - VSC9953_QSYS_OFFSET); + val = in_le32(&l2ana_reg->ana_tables.vlan_tidx); + val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid); + out_le32(&l2ana_reg->ana_tables.vlan_tidx, val); - l2dev_gcb = (struct vsc9953_devcpu_gcb *)(VSC9953_OFFSET + - VSC9953_DEVCPU_GCB); + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access, + VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ); - out_le32(&l2dev_gcb->chip_regs.soft_rst, - CONFIG_VSC9953_SOFT_SWC_RST_ENA); - timeout = 50000; - while ((in_le32(&l2dev_gcb->chip_regs.soft_rst) & - CONFIG_VSC9953_SOFT_SWC_RST_ENA) && --timeout) - udelay(1); /* busy wait for vsc9953 soft reset */ - if (timeout == 0) - debug("Timeout waiting for VSC9953 to reset\n"); + if (vsc9953_vlan_table_poll_idle() < 0) { + debug("VLAN table timeout\n"); + return; + } - out_le32(&l2sys_reg->sys.reset_cfg, CONFIG_VSC9953_MEM_ENABLE | - CONFIG_VSC9953_MEM_INIT); + val = in_le32(&l2ana_reg->ana_tables.vlan_tidx); + val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid); + out_le32(&l2ana_reg->ana_tables.vlan_tidx, val); + + val = in_le32(&l2ana_reg->ana_tables.vlan_access); + if (!add) { + val = bitfield_replace_by_mask(val, VSC9953_VLAN_CMD_MASK, + VSC9953_VLAN_CMD_WRITE) & + ~(bitfield_replace_by_mask(0, VSC9953_VLAN_PORT_MASK, + (1 << port_no))); + ; + } else { + val = bitfield_replace_by_mask(val, VSC9953_VLAN_CMD_MASK, + VSC9953_VLAN_CMD_WRITE) | + bitfield_replace_by_mask(0, VSC9953_VLAN_PORT_MASK, + (1 << port_no)); + } + out_le32(&l2ana_reg->ana_tables.vlan_access, val); - timeout = 50000; - while ((in_le32(&l2sys_reg->sys.reset_cfg) & - CONFIG_VSC9953_MEM_INIT) && --timeout) - udelay(1); /* busy wait for vsc9953 memory init */ - if (timeout == 0) - debug("Timeout waiting for VSC9953 memory to initialize\n"); + /* wait for VLAN table command to flush */ + if (vsc9953_vlan_table_poll_idle() < 0) { + debug("VLAN table timeout\n"); + return; + } +} - out_le32(&l2sys_reg->sys.reset_cfg, (in_le32(&l2sys_reg->sys.reset_cfg) - | CONFIG_VSC9953_CORE_ENABLE)); +/* show VLAN membership for a port */ +static void vsc9953_vlan_membership_show(int port_no) +{ + u32 val; + struct vsc9953_analyzer *l2ana_reg; + u32 vid; - /* VSC9953 Setting to be done once only */ - out_le32(&l2qsys_reg->sys.ext_cpu_cfg, 0x00000b00); + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); - for (i = 0; i < VSC9953_MAX_PORTS; i++) { - if (vsc9953_port_init(i)) - printf("Failed to initialize l2switch port %d\n", i); + printf("Port %d VLAN membership: ", port_no); - /* Enable VSC9953 GMII Ports Port ID 0 - 7 */ - if (VSC9953_INTERNAL_PORT_CHECK(i)) { - out_le32(&l2ana_reg->pfc[i].pfc_cfg, - CONFIG_VSC9953_PFC_FC_QSGMII); - out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i], - CONFIG_VSC9953_MAC_FC_CFG_QSGMII); - } else { - out_le32(&l2ana_reg->pfc[i].pfc_cfg, - CONFIG_VSC9953_PFC_FC); - out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i], - CONFIG_VSC9953_MAC_FC_CFG); + for (vid = 0; vid < VSC9953_MAX_VLAN; vid++) { + if (vsc9953_vlan_table_poll_idle() < 0) { + debug("VLAN table timeout\n"); + return; } - out_le32(&l2dev_gmii_reg->port_mode.clock_cfg, - CONFIG_VSC9953_CLOCK_CFG); - out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ena_cfg, - CONFIG_VSC9953_MAC_ENA_CFG); - out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_mode_cfg, - CONFIG_VSC9953_MAC_MODE_CFG); - out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ifg_cfg, - CONFIG_VSC9953_MAC_IFG_CFG); - /* mac_hdx_cfg varies with port id*/ - hdx_cfg = (CONFIG_VSC9953_MAC_HDX_CFG | (i << 16)); - out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_hdx_cfg, hdx_cfg); - out_le32(&l2sys_reg->sys.front_port_mode[i], - CONFIG_VSC9953_FRONT_PORT_MODE); - out_le32(&l2qsys_reg->sys.switch_port_mode[i], - CONFIG_VSC9953_PORT_ENA); - out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_maxlen_cfg, - CONFIG_VSC9953_MAC_MAX_LEN); - out_le32(&l2sys_reg->pause_cfg.pause_cfg[i], - CONFIG_VSC9953_PAUSE_CFG); - /* WAIT FOR 2 us*/ - udelay(2); - l2dev_gmii_reg = (struct vsc9953_dev_gmii *)( - (char *)l2dev_gmii_reg - + T1040_SWITCH_GMII_DEV_OFFSET); + val = in_le32(&l2ana_reg->ana_tables.vlan_tidx); + val = bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, + vid); + out_le32(&l2ana_reg->ana_tables.vlan_tidx, val); - /* Initialize Lynx PHY Wrappers */ - phy_addr = 0; - if (vsc9953_l2sw.port[i].enet_if == - PHY_INTERFACE_MODE_QSGMII) - phy_addr = (i + 0x4) & 0x1F; - else if (vsc9953_l2sw.port[i].enet_if == - PHY_INTERFACE_MODE_SGMII) - phy_addr = (i + 1) & 0x1F; - - if (phy_addr) { - /* SGMII IF mode + AN enable */ - vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, - 0x14, PHY_SGMII_IF_MODE_AN | - PHY_SGMII_IF_MODE_SGMII); - /* Dev ability according to SGMII specification */ - vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, - 0x4, PHY_SGMII_DEV_ABILITY_SGMII); - /* Adjust link timer for SGMII - * 1.6 ms in units of 8 ns = 2 * 10^5 = 0x30d40 - */ - vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, - 0x13, 0x0003); - vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, - 0x12, 0x0d40); - /* Restart AN */ - vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, - 0x0, PHY_SGMII_CR_DEF_VAL | - PHY_SGMII_CR_RESET_AN); + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access, + VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ); - timeout = 50000; - while ((vsc9953_mdio_read(&l2dev_gcb->mii_mng[0], - phy_addr, 0x01) & 0x0020) && --timeout) - udelay(1); /* wait for AN to complete */ - if (timeout == 0) - debug("Timeout waiting for AN to complete\n"); + if (vsc9953_vlan_table_poll_idle() < 0) { + debug("VLAN table timeout\n"); + return; } + + val = in_le32(&l2ana_reg->ana_tables.vlan_access); + + if (bitfield_extract_by_mask(val, VSC9953_VLAN_PORT_MASK) & + (1 << port_no)) + printf("%d ", vid); } + printf("\n"); +} +#endif - printf("VSC9953 L2 switch initialized\n"); - return; +/* vlan table set/clear all membership of vid */ +static void vsc9953_vlan_table_membership_all_set(int vid, int set_member) +{ + uint val; + struct vsc9953_analyzer *l2ana_reg; + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + if (vsc9953_vlan_table_poll_idle() < 0) { + debug("VLAN table timeout\n"); + return; + } + + /* read current vlan configuration */ + val = in_le32(&l2ana_reg->ana_tables.vlan_tidx); + out_le32(&l2ana_reg->ana_tables.vlan_tidx, + bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid)); + + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access, + VSC9953_VLAN_CMD_MASK, VSC9953_VLAN_CMD_READ); + + if (vsc9953_vlan_table_poll_idle() < 0) { + debug("VLAN table timeout\n"); + return; + } + + val = in_le32(&l2ana_reg->ana_tables.vlan_tidx); + out_le32(&l2ana_reg->ana_tables.vlan_tidx, + bitfield_replace_by_mask(val, VSC9953_ANA_TBL_VID_MASK, vid)); + + clrsetbits_le32(&l2ana_reg->ana_tables.vlan_access, + VSC9953_VLAN_PORT_MASK | VSC9953_VLAN_CMD_MASK, + VSC9953_VLAN_CMD_WRITE | + (set_member ? VSC9953_VLAN_PORT_MASK : 0)); } -#ifdef CONFIG_VSC9953_CMD -/* Enable/disable status of a VSC9953 port */ -static void vsc9953_port_status_set(int port_nr, u8 enabled) +#ifdef CONFIG_CMD_ETHSW +/* Get PVID of a VSC9953 port */ +static int vsc9953_port_vlan_pvid_get(int port_nr, int *pvid) { - u32 val; - struct vsc9953_qsys_reg *l2qsys_reg; + u32 val; + struct vsc9953_analyzer *l2ana_reg; /* Administrative down */ - if (vsc9953_l2sw.port[port_nr].enabled == 0) + if (vsc9953_l2sw.port[port_nr].enabled) { + printf("Port %d is administrative down\n", port_nr); + return -1; + } + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + /* Get ingress PVID */ + val = in_le32(&l2ana_reg->port[port_nr].vlan_cfg); + *pvid = bitfield_extract_by_mask(val, VSC9953_VLAN_CFG_VID_MASK); + + return 0; +} +#endif + +/* Set PVID for a VSC9953 port */ +static void vsc9953_port_vlan_pvid_set(int port_no, int pvid) +{ + uint val; + struct vsc9953_analyzer *l2ana_reg; + struct vsc9953_rew_reg *l2rew_reg; + + /* Administrative down */ + if (!vsc9953_l2sw.port[port_no].enabled) { + printf("Port %d is administrative down\n", port_no); return; + } - l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET + - VSC9953_QSYS_OFFSET); + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET + + VSC9953_REW_OFFSET); + + /* Set PVID on ingress */ + val = in_le32(&l2ana_reg->port[port_no].vlan_cfg); + val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_VID_MASK, pvid); + out_le32(&l2ana_reg->port[port_no].vlan_cfg, val); + + /* Set PVID on egress */ + val = in_le32(&l2rew_reg->port[port_no].port_vlan_cfg); + val = bitfield_replace_by_mask(val, VSC9953_PORT_VLAN_CFG_VID_MASK, + pvid); + out_le32(&l2rew_reg->port[port_no].port_vlan_cfg, val); +} + +static void vsc9953_port_all_vlan_pvid_set(int pvid) +{ + int i; + + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_port_vlan_pvid_set(i, pvid); +} + +/* Enable/disable vlan aware of a VSC9953 port */ +static void vsc9953_port_vlan_aware_set(int port_no, int enabled) +{ + struct vsc9953_analyzer *l2ana_reg; - val = in_le32(&l2qsys_reg->sys.switch_port_mode[port_nr]); - if (enabled == 1) - val |= (1 << 13); + /* Administrative down */ + if (!vsc9953_l2sw.port[port_no].enabled) { + printf("Port %d is administrative down\n", port_no); + return; + } + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + if (enabled) + setbits_le32(&l2ana_reg->port[port_no].vlan_cfg, + VSC9953_VLAN_CFG_AWARE_ENA); else - val &= ~(1 << 13); + clrbits_le32(&l2ana_reg->port[port_no].vlan_cfg, + VSC9953_VLAN_CFG_AWARE_ENA); +} + +/* Set all VSC9953 ports' vlan aware */ +static void vsc9953_port_all_vlan_aware_set(int enabled) +{ + int i; - out_le32(&l2qsys_reg->sys.switch_port_mode[port_nr], val); + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_port_vlan_aware_set(i, enabled); } -/* Set all VSC9953 ports' status */ -static void vsc9953_port_all_status_set(u8 enabled) +/* Enable/disable vlan pop count of a VSC9953 port */ +static void vsc9953_port_vlan_popcnt_set(int port_no, int popcnt) { - int i; + uint val; + struct vsc9953_analyzer *l2ana_reg; + + /* Administrative down */ + if (!vsc9953_l2sw.port[port_no].enabled) { + printf("Port %d is administrative down\n", port_no); + return; + } + + if (popcnt > 3 || popcnt < 0) { + printf("Invalid pop count value: %d\n", port_no); + return; + } + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + val = in_le32(&l2ana_reg->port[port_no].vlan_cfg); + val = bitfield_replace_by_mask(val, VSC9953_VLAN_CFG_POP_CNT_MASK, + popcnt); + out_le32(&l2ana_reg->port[port_no].vlan_cfg, val); +} + +/* Set all VSC9953 ports' pop count */ +static void vsc9953_port_all_vlan_poncnt_set(int popcnt) +{ + int i; for (i = 0; i < VSC9953_MAX_PORTS; i++) - vsc9953_port_status_set(i, enabled); + vsc9953_port_vlan_popcnt_set(i, popcnt); } -/* Start autonegotiation for a VSC9953 PHY */ -static void vsc9953_phy_autoneg(int port_nr) +/* Enable/disable learning for frames dropped due to ingress filtering */ +static void vsc9953_vlan_ingr_fltr_learn_drop(int enable) +{ + struct vsc9953_analyzer *l2ana_reg; + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + if (enable) + setbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK); + else + clrbits_le32(&l2ana_reg->ana.adv_learn, VSC9953_VLAN_CHK); +} + +/* Egress untag modes of a VSC9953 port */ +enum egress_untag_mode { + EGRESS_UNTAG_ALL = 0, + EGRESS_UNTAG_PVID_AND_ZERO, + EGRESS_UNTAG_ZERO, + EGRESS_UNTAG_NONE, +}; + +#ifdef CONFIG_CMD_ETHSW +/* Get egress tagging configuration for a VSC9953 port */ +static int vsc9953_port_vlan_egr_untag_get(int port_no, + enum egress_untag_mode *mode) { - if (!vsc9953_l2sw.port[port_nr].phydev) + u32 val; + struct vsc9953_rew_reg *l2rew_reg; + + /* Administrative down */ + if (!vsc9953_l2sw.port[port_no].enabled) { + printf("Port %d is administrative down\n", port_no); + return -1; + } + + l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET + + VSC9953_REW_OFFSET); + + val = in_le32(&l2rew_reg->port[port_no].port_tag_cfg); + + switch (val & VSC9953_TAG_CFG_MASK) { + case VSC9953_TAG_CFG_NONE: + *mode = EGRESS_UNTAG_ALL; + return 0; + case VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO: + *mode = EGRESS_UNTAG_PVID_AND_ZERO; + return 0; + case VSC9953_TAG_CFG_ALL_BUT_ZERO: + *mode = EGRESS_UNTAG_ZERO; + return 0; + case VSC9953_TAG_CFG_ALL: + *mode = EGRESS_UNTAG_NONE; + return 0; + default: + printf("Unknown egress tagging configuration for port %d\n", + port_no); + return -1; + } +} + +/* Show egress tagging configuration for a VSC9953 port */ +static void vsc9953_port_vlan_egr_untag_show(int port_no) +{ + enum egress_untag_mode mode; + + if (vsc9953_port_vlan_egr_untag_get(port_no, &mode)) { + printf("%7d\t%17s\n", port_no, "-"); return; + } - if (vsc9953_l2sw.port[port_nr].phydev->drv->startup( - vsc9953_l2sw.port[port_nr].phydev)) - printf("Failed to start PHY for port %d\n", port_nr); + printf("%7d\t", port_no); + switch (mode) { + case EGRESS_UNTAG_ALL: + printf("%17s\n", "all"); + break; + case EGRESS_UNTAG_NONE: + printf("%17s\n", "none"); + break; + case EGRESS_UNTAG_PVID_AND_ZERO: + printf("%17s\n", "PVID and 0"); + break; + case EGRESS_UNTAG_ZERO: + printf("%17s\n", "0"); + break; + default: + printf("%17s\n", "-"); + } } +#endif -/* Start autonegotiation for all VSC9953 PHYs */ -static void vsc9953_phy_all_autoneg(void) +static void vsc9953_port_vlan_egr_untag_set(int port_no, + enum egress_untag_mode mode) { - int i; + struct vsc9953_rew_reg *l2rew_reg; + + /* Administrative down */ + if (!vsc9953_l2sw.port[port_no].enabled) { + printf("Port %d is administrative down\n", port_no); + return; + } + + l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET + + VSC9953_REW_OFFSET); + + switch (mode) { + case EGRESS_UNTAG_ALL: + clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, + VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_NONE); + break; + case EGRESS_UNTAG_PVID_AND_ZERO: + clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, + VSC9953_TAG_CFG_MASK, + VSC9953_TAG_CFG_ALL_BUT_PVID_ZERO); + break; + case EGRESS_UNTAG_ZERO: + clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, + VSC9953_TAG_CFG_MASK, + VSC9953_TAG_CFG_ALL_BUT_ZERO); + break; + case EGRESS_UNTAG_NONE: + clrsetbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, + VSC9953_TAG_CFG_MASK, VSC9953_TAG_CFG_ALL); + break; + default: + printf("Unknown untag mode for port %d\n", port_no); + } +} + +static void vsc9953_port_all_vlan_egress_untagged_set( + enum egress_untag_mode mode) +{ + int i; for (i = 0; i < VSC9953_MAX_PORTS; i++) - vsc9953_phy_autoneg(i); + vsc9953_port_vlan_egr_untag_set(i, mode); +} + +#ifdef CONFIG_CMD_ETHSW + +/* Enable/disable status of a VSC9953 port */ +static void vsc9953_port_status_set(int port_no, u8 enabled) +{ + struct vsc9953_qsys_reg *l2qsys_reg; + + /* Administrative down */ + if (!vsc9953_l2sw.port[port_no].enabled) + return; + + l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET + + VSC9953_QSYS_OFFSET); + + if (enabled) + setbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no], + VSC9953_PORT_ENA); + else + clrbits_le32(&l2qsys_reg->sys.switch_port_mode[port_no], + VSC9953_PORT_ENA); +} + +/* Start autonegotiation for a VSC9953 PHY */ +static void vsc9953_phy_autoneg(int port_no) +{ + if (!vsc9953_l2sw.port[port_no].phydev) + return; + + if (vsc9953_l2sw.port[port_no].phydev->drv->startup( + vsc9953_l2sw.port[port_no].phydev)) + printf("Failed to start PHY for port %d\n", port_no); } /* Print a VSC9953 port's configuration */ -static void vsc9953_port_config_show(int port) +static void vsc9953_port_config_show(int port_no) { - int speed; - int duplex; - int link; - u8 enabled; - u32 val; - struct vsc9953_qsys_reg *l2qsys_reg; + int speed; + int duplex; + int link; + u8 enabled; + u32 val; + struct vsc9953_qsys_reg *l2qsys_reg; l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET + VSC9953_QSYS_OFFSET); - val = in_le32(&l2qsys_reg->sys.switch_port_mode[port]); - enabled = vsc9953_l2sw.port[port].enabled & - ((val & 0x00002000) >> 13); + val = in_le32(&l2qsys_reg->sys.switch_port_mode[port_no]); + enabled = vsc9953_l2sw.port[port_no].enabled && + (val & VSC9953_PORT_ENA); /* internal ports (8 and 9) are fixed */ - if (VSC9953_INTERNAL_PORT_CHECK(port)) { + if (VSC9953_INTERNAL_PORT_CHECK(port_no)) { link = 1; speed = SPEED_2500; duplex = DUPLEX_FULL; } else { - if (vsc9953_l2sw.port[port].phydev) { - link = vsc9953_l2sw.port[port].phydev->link; - speed = vsc9953_l2sw.port[port].phydev->speed; - duplex = vsc9953_l2sw.port[port].phydev->duplex; + if (vsc9953_l2sw.port[port_no].phydev) { + link = vsc9953_l2sw.port[port_no].phydev->link; + speed = vsc9953_l2sw.port[port_no].phydev->speed; + duplex = vsc9953_l2sw.port[port_no].phydev->duplex; } else { link = -1; speed = -1; @@ -396,7 +660,7 @@ static void vsc9953_port_config_show(int port) } } - printf("%8d ", port); + printf("%8d ", port_no); printf("%8s ", enabled == 1 ? "enabled" : "disabled"); printf("%8s ", link == 1 ? "up" : "down"); @@ -423,75 +687,1575 @@ static void vsc9953_port_config_show(int port) printf("%8s\n", duplex == DUPLEX_FULL ? "full" : "half"); } -/* Print VSC9953 ports' configuration */ -static void vsc9953_port_all_config_show(void) +/* Show VSC9953 ports' statistics */ +static void vsc9953_port_statistics_show(int port_no) { - int i; + u32 rx_val; + u32 tx_val; + struct vsc9953_system_reg *l2sys_reg; - for (i = 0; i < VSC9953_MAX_PORTS; i++) - vsc9953_port_config_show(i); + /* Administrative down */ + if (!vsc9953_l2sw.port[port_no].enabled) { + printf("Port %d is administrative down\n", port_no); + return; + } + + l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET + + VSC9953_SYS_OFFSET); + + printf("Statistics for L2 Switch port %d:\n", port_no); + + /* Set counter view for our port */ + out_le32(&l2sys_reg->sys.stat_cfg, port_no); + +#define VSC9953_STATS_PRINTF "%-15s %10u" + + /* Get number of Rx and Tx frames */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_short) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_frag) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_jabber) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_long) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_64) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_65_127) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_128_255) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_256_511) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_512_1023) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_1024_1526) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_jumbo); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64) + + in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127) + + in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255) + + in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511) + + in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023) + + in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526) + + in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx frames:", rx_val, "Tx frames:", tx_val); + + /* Get number of Rx and Tx bytes */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_oct); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_oct); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx bytes:", rx_val, "Tx bytes:", tx_val); + + /* Get number of Rx frames received ok and Tx frames sent ok */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_0) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_1) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_2) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_3) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_4) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_5) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_6) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_yellow_prio_7) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_0) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_1) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_2) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_3) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_4) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_5) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_6) + + in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_green_prio_7); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64) + + in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127) + + in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255) + + in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511) + + in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023) + + in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526) + + in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx frames ok:", rx_val, "Tx frames ok:", tx_val); + + /* Get number of Rx and Tx unicast frames */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_uc); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_uc); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx unicast:", rx_val, "Tx unicast:", tx_val); + + /* Get number of Rx and Tx broadcast frames */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_bc); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_bc); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx broadcast:", rx_val, "Tx broadcast:", tx_val); + + /* Get number of Rx and Tx frames of 64B */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_64); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_64); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx 64B:", rx_val, "Tx 64B:", tx_val); + + /* Get number of Rx and Tx frames with sizes between 65B and 127B */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_65_127); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_65_127); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx 65B-127B:", rx_val, "Tx 65B-127B:", tx_val); + + /* Get number of Rx and Tx frames with sizes between 128B and 255B */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_128_255); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_128_255); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx 128B-255B:", rx_val, "Tx 128B-255B:", tx_val); + + /* Get number of Rx and Tx frames with sizes between 256B and 511B */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_256_511); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_256_511); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx 256B-511B:", rx_val, "Tx 256B-511B:", tx_val); + + /* Get number of Rx and Tx frames with sizes between 512B and 1023B */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_512_1023); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_512_1023); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx 512B-1023B:", rx_val, "Tx 512B-1023B:", tx_val); + + /* Get number of Rx and Tx frames with sizes between 1024B and 1526B */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_1024_1526); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_1024_1526); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx 1024B-1526B:", rx_val, "Tx 1024B-1526B:", tx_val); + + /* Get number of Rx and Tx jumbo frames */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_sz_jumbo); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_sz_jumbo); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx jumbo:", rx_val, "Tx jumbo:", tx_val); + + /* Get number of Rx and Tx dropped frames */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_cat_drop) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_tail) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_0) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_1) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_2) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_3) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_4) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_5) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_6) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_yellow_prio_7) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_0) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_1) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_2) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_3) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_4) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_5) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_6) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_green_prio_7); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_drop) + + in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_aged); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx drops:", rx_val, "Tx drops:", tx_val); + + /* + * Get number of Rx frames with CRC or alignment errors + * and number of detected Tx collisions + */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_crc); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_col); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx CRC&align:", rx_val, "Tx coll:", tx_val); + + /* + * Get number of Rx undersized frames and + * number of Tx aged frames + */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_short); + tx_val = in_le32(&l2sys_reg->stat.tx_cntrs.c_tx_aged); + printf(VSC9953_STATS_PRINTF"\t\t"VSC9953_STATS_PRINTF"\n", + "Rx undersize:", rx_val, "Tx aged:", tx_val); + + /* Get number of Rx oversized frames */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_long); + printf(VSC9953_STATS_PRINTF"\n", "Rx oversized:", rx_val); + + /* Get number of Rx fragmented frames */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_frag); + printf(VSC9953_STATS_PRINTF"\n", "Rx fragments:", rx_val); + + /* Get number of Rx jabber errors */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_jabber); + printf(VSC9953_STATS_PRINTF"\n", "Rx jabbers:", rx_val); + + /* + * Get number of Rx frames filtered due to classification rules or + * no destination ports + */ + rx_val = in_le32(&l2sys_reg->stat.rx_cntrs.c_rx_cat_drop) + + in_le32(&l2sys_reg->stat.drop_cntrs.c_dr_local); + printf(VSC9953_STATS_PRINTF"\n", "Rx filtered:", rx_val); + + printf("\n"); } -/* function to interpret commands starting with "ethsw " */ -static int do_ethsw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +/* Clear statistics for a VSC9953 port */ +static void vsc9953_port_statistics_clear(int port_no) { - u8 enable; - u32 port; + struct vsc9953_system_reg *l2sys_reg; - if (argc < 4) + /* Administrative down */ + if (!vsc9953_l2sw.port[port_no].enabled) { + printf("Port %d is administrative down\n", port_no); + return; + } + + l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET + + VSC9953_SYS_OFFSET); + + /* Clear all counter groups for our ports */ + out_le32(&l2sys_reg->sys.stat_cfg, port_no | + VSC9953_STAT_CLEAR_RX | VSC9953_STAT_CLEAR_TX | + VSC9953_STAT_CLEAR_DR); +} + +enum port_learn_mode { + PORT_LEARN_NONE, + PORT_LEARN_AUTO +}; + +/* Set learning configuration for a VSC9953 port */ +static void vsc9953_port_learn_mode_set(int port_no, enum port_learn_mode mode) +{ + struct vsc9953_analyzer *l2ana_reg; + + /* Administrative down */ + if (!vsc9953_l2sw.port[port_no].enabled) { + printf("Port %d is administrative down\n", port_no); + return; + } + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + switch (mode) { + case PORT_LEARN_NONE: + clrbits_le32(&l2ana_reg->port[port_no].port_cfg, + VSC9953_PORT_CFG_LEARN_DROP | + VSC9953_PORT_CFG_LEARN_CPU | + VSC9953_PORT_CFG_LEARN_AUTO | + VSC9953_PORT_CFG_LEARN_ENA); + break; + case PORT_LEARN_AUTO: + clrsetbits_le32(&l2ana_reg->port[port_no].port_cfg, + VSC9953_PORT_CFG_LEARN_DROP | + VSC9953_PORT_CFG_LEARN_CPU, + VSC9953_PORT_CFG_LEARN_ENA | + VSC9953_PORT_CFG_LEARN_AUTO); + break; + default: + printf("Unknown learn mode for port %d\n", port_no); + } +} + +/* Get learning configuration for a VSC9953 port */ +static int vsc9953_port_learn_mode_get(int port_no, enum port_learn_mode *mode) +{ + u32 val; + struct vsc9953_analyzer *l2ana_reg; + + /* Administrative down */ + if (!vsc9953_l2sw.port[port_no].enabled) { + printf("Port %d is administrative down\n", port_no); return -1; + } + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + /* For now we only support HW learning (auto) and no learning */ + val = in_le32(&l2ana_reg->port[port_no].port_cfg); + if ((val & (VSC9953_PORT_CFG_LEARN_ENA | + VSC9953_PORT_CFG_LEARN_AUTO)) == + (VSC9953_PORT_CFG_LEARN_ENA | VSC9953_PORT_CFG_LEARN_AUTO)) + *mode = PORT_LEARN_AUTO; + else + *mode = PORT_LEARN_NONE; + + return 0; +} - if (strcmp(argv[1], "port")) +/* wait for FDB to become available */ +static int vsc9953_mac_table_poll_idle(void) +{ + struct vsc9953_analyzer *l2ana_reg; + u32 timeout; + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + timeout = 50000; + while (((in_le32(&l2ana_reg->ana_tables.mac_access) & + VSC9953_MAC_CMD_MASK) != + VSC9953_MAC_CMD_IDLE) && --timeout) + udelay(1); + + return timeout ? 0 : -EBUSY; +} + +/* enum describing available commands for the MAC table */ +enum mac_table_cmd { + MAC_TABLE_READ, + MAC_TABLE_LOOKUP, + MAC_TABLE_WRITE, + MAC_TABLE_LEARN, + MAC_TABLE_FORGET, + MAC_TABLE_GET_NEXT, + MAC_TABLE_AGE, +}; + +/* Issues a command to the FDB table */ +static int vsc9953_mac_table_cmd(enum mac_table_cmd cmd) +{ + struct vsc9953_analyzer *l2ana_reg; + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + switch (cmd) { + case MAC_TABLE_READ: + clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, + VSC9953_MAC_CMD_MASK | VSC9953_MAC_CMD_VALID, + VSC9953_MAC_CMD_READ); + break; + case MAC_TABLE_LOOKUP: + clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, + VSC9953_MAC_CMD_MASK, VSC9953_MAC_CMD_READ | + VSC9953_MAC_CMD_VALID); + break; + case MAC_TABLE_WRITE: + clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, + VSC9953_MAC_CMD_MASK | + VSC9953_MAC_ENTRYTYPE_MASK, + VSC9953_MAC_CMD_WRITE | + VSC9953_MAC_ENTRYTYPE_LOCKED); + break; + case MAC_TABLE_LEARN: + clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, + VSC9953_MAC_CMD_MASK | + VSC9953_MAC_ENTRYTYPE_MASK, + VSC9953_MAC_CMD_LEARN | + VSC9953_MAC_ENTRYTYPE_LOCKED | + VSC9953_MAC_CMD_VALID); + break; + case MAC_TABLE_FORGET: + clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, + VSC9953_MAC_CMD_MASK | + VSC9953_MAC_ENTRYTYPE_MASK, + VSC9953_MAC_CMD_FORGET); + break; + case MAC_TABLE_GET_NEXT: + clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, + VSC9953_MAC_CMD_MASK | + VSC9953_MAC_ENTRYTYPE_MASK, + VSC9953_MAC_CMD_NEXT); + break; + case MAC_TABLE_AGE: + clrsetbits_le32(&l2ana_reg->ana_tables.mac_access, + VSC9953_MAC_CMD_MASK | + VSC9953_MAC_ENTRYTYPE_MASK, + VSC9953_MAC_CMD_AGE); + break; + default: + printf("Unknown MAC table command\n"); + } + + if (vsc9953_mac_table_poll_idle() < 0) { + debug("MAC table timeout\n"); return -1; + } - if (!strcmp(argv[3], "show")) { - if (!strcmp(argv[2], "all")) { - vsc9953_phy_all_autoneg(); - printf("%8s %8s %8s %8s %8s\n", - "Port", "Status", "Link", "Speed", - "Duplex"); - vsc9953_port_all_config_show(); - return 0; - } else { - port = simple_strtoul(argv[2], NULL, 10); - if (!VSC9953_PORT_CHECK(port)) - return -1; - vsc9953_phy_autoneg(port); - printf("%8s %8s %8s %8s %8s\n", - "Port", "Status", "Link", "Speed", - "Duplex"); - vsc9953_port_config_show(port); - return 0; - } - } else if (!strcmp(argv[3], "enable")) { - enable = 1; - } else if (!strcmp(argv[3], "disable")) { - enable = 0; + return 0; +} + +/* show the FDB entries that correspond to a port and a VLAN */ +static void vsc9953_mac_table_show(int port_no, int vid) +{ + int rc[VSC9953_MAX_PORTS]; + enum port_learn_mode mode[VSC9953_MAX_PORTS]; + int i; + u32 val; + u32 vlan; + u32 mach; + u32 macl; + u32 dest_indx; + struct vsc9953_analyzer *l2ana_reg; + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + /* disable auto learning */ + if (port_no == ETHSW_CMD_PORT_ALL) { + for (i = 0; i < VSC9953_MAX_PORTS; i++) { + rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]); + if (!rc[i] && mode[i] != PORT_LEARN_NONE) + vsc9953_port_learn_mode_set(i, PORT_LEARN_NONE); + } + } else { + rc[port_no] = vsc9953_port_learn_mode_get(port_no, + &mode[port_no]); + if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE) + vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE); + } + + /* write port and vid to get selected FDB entries */ + val = in_le32(&l2ana_reg->ana.anag_efil); + if (port_no != ETHSW_CMD_PORT_ALL) { + val = bitfield_replace_by_mask(val, VSC9953_AGE_PORT_MASK, + port_no) | VSC9953_AGE_PORT_EN; + } + if (vid != ETHSW_CMD_VLAN_ALL) { + val = bitfield_replace_by_mask(val, VSC9953_AGE_VID_MASK, + vid) | VSC9953_AGE_VID_EN; + } + out_le32(&l2ana_reg->ana.anag_efil, val); + + /* set MAC and VLAN to 0 to look from beginning */ + clrbits_le32(&l2ana_reg->ana_tables.mach_data, + VSC9953_MAC_VID_MASK | VSC9953_MAC_MACH_MASK); + out_le32(&l2ana_reg->ana_tables.macl_data, 0); + + /* get entries */ + printf("%10s %17s %5s %4s\n", "EntryType", "MAC", "PORT", "VID"); + do { + if (vsc9953_mac_table_cmd(MAC_TABLE_GET_NEXT) < 0) { + debug("GET NEXT MAC table command failed\n"); + break; + } + + val = in_le32(&l2ana_reg->ana_tables.mac_access); + + /* get out when an invalid entry is found */ + if (!(val & VSC9953_MAC_CMD_VALID)) + break; + + switch (val & VSC9953_MAC_ENTRYTYPE_MASK) { + case VSC9953_MAC_ENTRYTYPE_NORMAL: + printf("%10s ", "Dynamic"); + break; + case VSC9953_MAC_ENTRYTYPE_LOCKED: + printf("%10s ", "Static"); + break; + case VSC9953_MAC_ENTRYTYPE_IPV4MCAST: + printf("%10s ", "IPv4 Mcast"); + break; + case VSC9953_MAC_ENTRYTYPE_IPV6MCAST: + printf("%10s ", "IPv6 Mcast"); + break; + default: + printf("%10s ", "Unknown"); + } + + dest_indx = bitfield_extract_by_mask(val, + VSC9953_MAC_DESTIDX_MASK); + + val = in_le32(&l2ana_reg->ana_tables.mach_data); + vlan = bitfield_extract_by_mask(val, VSC9953_MAC_VID_MASK); + mach = bitfield_extract_by_mask(val, VSC9953_MAC_MACH_MASK); + macl = in_le32(&l2ana_reg->ana_tables.macl_data); + + printf("%02x:%02x:%02x:%02x:%02x:%02x ", (mach >> 8) & 0xff, + mach & 0xff, (macl >> 24) & 0xff, (macl >> 16) & 0xff, + (macl >> 8) & 0xff, macl & 0xff); + printf("%5d ", dest_indx); + printf("%4d\n", vlan); + } while (1); + + /* set learning mode to previous value */ + if (port_no == ETHSW_CMD_PORT_ALL) { + for (i = 0; i < VSC9953_MAX_PORTS; i++) { + if (!rc[i] && mode[i] != PORT_LEARN_NONE) + vsc9953_port_learn_mode_set(i, mode[i]); + } } else { + /* If administrative down, skip */ + if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE) + vsc9953_port_learn_mode_set(port_no, mode[port_no]); + } + + /* reset FDB port and VLAN FDB selection */ + clrbits_le32(&l2ana_reg->ana.anag_efil, VSC9953_AGE_PORT_EN | + VSC9953_AGE_PORT_MASK | VSC9953_AGE_VID_EN | + VSC9953_AGE_VID_MASK); +} + +/* Add a static FDB entry */ +static int vsc9953_mac_table_add(u8 port_no, uchar mac[6], int vid) +{ + u32 val; + struct vsc9953_analyzer *l2ana_reg; + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + val = in_le32(&l2ana_reg->ana_tables.mach_data); + val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | + (mac[0] << 8) | (mac[1] << 0); + out_le32(&l2ana_reg->ana_tables.mach_data, val); + + out_le32(&l2ana_reg->ana_tables.macl_data, + (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | + (mac[5] << 0)); + + /* set on which port is the MAC address added */ + val = in_le32(&l2ana_reg->ana_tables.mac_access); + val = bitfield_replace_by_mask(val, VSC9953_MAC_DESTIDX_MASK, port_no); + out_le32(&l2ana_reg->ana_tables.mac_access, val); + + if (vsc9953_mac_table_cmd(MAC_TABLE_LEARN) < 0) + return -1; + + /* check if the MAC address was indeed added */ + val = in_le32(&l2ana_reg->ana_tables.mach_data); + val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | + (mac[0] << 8) | (mac[1] << 0); + out_le32(&l2ana_reg->ana_tables.mach_data, val); + + out_le32(&l2ana_reg->ana_tables.macl_data, + (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | + (mac[5] << 0)); + + if (vsc9953_mac_table_cmd(MAC_TABLE_READ) < 0) + return -1; + + val = in_le32(&l2ana_reg->ana_tables.mac_access); + + if ((port_no != bitfield_extract_by_mask(val, + VSC9953_MAC_DESTIDX_MASK))) { + printf("Failed to add MAC address\n"); return -1; } + return 0; +} - if (!strcmp(argv[2], "all")) { - vsc9953_port_all_status_set(enable); - return 0; +/* Delete a FDB entry */ +static int vsc9953_mac_table_del(uchar mac[6], u16 vid) +{ + u32 val; + struct vsc9953_analyzer *l2ana_reg; + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + /* check first if MAC entry is present */ + val = in_le32(&l2ana_reg->ana_tables.mach_data); + val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | + (mac[0] << 8) | (mac[1] << 0); + out_le32(&l2ana_reg->ana_tables.mach_data, val); + + out_le32(&l2ana_reg->ana_tables.macl_data, + (mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | + (mac[5] << 0)); + + if (vsc9953_mac_table_cmd(MAC_TABLE_LOOKUP) < 0) { + debug("Lookup in the MAC table failed\n"); + return -1; + } + + if (!(in_le32(&l2ana_reg->ana_tables.mac_access) & + VSC9953_MAC_CMD_VALID)) { + printf("The MAC address: %02x:%02x:%02x:%02x:%02x:%02x ", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + printf("VLAN: %d does not exist.\n", vid); + return -1; + } + + /* FDB entry found, proceed to delete */ + val = in_le32(&l2ana_reg->ana_tables.mach_data); + val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | + (mac[0] << 8) | (mac[1] << 0); + out_le32(&l2ana_reg->ana_tables.mach_data, val); + + out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) | + (mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0)); + + if (vsc9953_mac_table_cmd(MAC_TABLE_FORGET) < 0) + return -1; + + /* check if the MAC entry is still in FDB */ + val = in_le32(&l2ana_reg->ana_tables.mach_data); + val = bitfield_replace_by_mask(val, VSC9953_MACHDATA_VID_MASK, vid) | + (mac[0] << 8) | (mac[1] << 0); + out_le32(&l2ana_reg->ana_tables.mach_data, val); + + out_le32(&l2ana_reg->ana_tables.macl_data, (mac[2] << 24) | + (mac[3] << 16) | (mac[4] << 8) | (mac[5] << 0)); + + if (vsc9953_mac_table_cmd(MAC_TABLE_LOOKUP) < 0) { + debug("Lookup in the MAC table failed\n"); + return -1; + } + if (in_le32(&l2ana_reg->ana_tables.mac_access) & + VSC9953_MAC_CMD_VALID) { + printf("Failed to delete MAC address\n"); + return -1; + } + + return 0; +} + +/* age the unlocked entries in FDB */ +static void vsc9953_mac_table_age(int port_no, int vid) +{ + int rc[VSC9953_MAX_PORTS]; + enum port_learn_mode mode[VSC9953_MAX_PORTS]; + u32 val; + int i; + struct vsc9953_analyzer *l2ana_reg; + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + /* set port and VID for selective aging */ + val = in_le32(&l2ana_reg->ana.anag_efil); + if (port_no != ETHSW_CMD_PORT_ALL) { + /* disable auto learning */ + rc[port_no] = vsc9953_port_learn_mode_get(port_no, + &mode[port_no]); + if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE) + vsc9953_port_learn_mode_set(port_no, PORT_LEARN_NONE); + + val = bitfield_replace_by_mask(val, VSC9953_AGE_PORT_MASK, + port_no) | VSC9953_AGE_PORT_EN; } else { - port = simple_strtoul(argv[2], NULL, 10); - if (!VSC9953_PORT_CHECK(port)) - return -1; - vsc9953_port_status_set(port, enable); - return 0; + /* disable auto learning on all ports */ + for (i = 0; i < VSC9953_MAX_PORTS; i++) { + rc[i] = vsc9953_port_learn_mode_get(i, &mode[i]); + if (!rc[i] && mode[i] != PORT_LEARN_NONE) + vsc9953_port_learn_mode_set(i, PORT_LEARN_NONE); + } + } + + if (vid != ETHSW_CMD_VLAN_ALL) { + val = bitfield_replace_by_mask(val, VSC9953_AGE_VID_MASK, vid) | + VSC9953_AGE_VID_EN; + } + out_le32(&l2ana_reg->ana.anag_efil, val); + + /* age the dynamic FDB entries */ + vsc9953_mac_table_cmd(MAC_TABLE_AGE); + + /* clear previously set port and VID */ + clrbits_le32(&l2ana_reg->ana.anag_efil, VSC9953_AGE_PORT_EN | + VSC9953_AGE_PORT_MASK | VSC9953_AGE_VID_EN | + VSC9953_AGE_VID_MASK); + + if (port_no != ETHSW_CMD_PORT_ALL) { + if (!rc[port_no] && mode[port_no] != PORT_LEARN_NONE) + vsc9953_port_learn_mode_set(port_no, mode[port_no]); + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) { + if (!rc[i] && mode[i] != PORT_LEARN_NONE) + vsc9953_port_learn_mode_set(i, mode[i]); + } + } +} + +/* Delete all the dynamic FDB entries */ +static void vsc9953_mac_table_flush(int port, int vid) +{ + vsc9953_mac_table_age(port, vid); + vsc9953_mac_table_age(port, vid); +} + +enum egress_vlan_tag { + EGR_TAG_CLASS = 0, + EGR_TAG_PVID, +}; + +/* Set egress tag mode for a VSC9953 port */ +static void vsc9953_port_vlan_egress_tag_set(int port_no, + enum egress_vlan_tag mode) +{ + struct vsc9953_rew_reg *l2rew_reg; + + l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET + + VSC9953_REW_OFFSET); + + switch (mode) { + case EGR_TAG_CLASS: + clrbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, + VSC9953_TAG_VID_PVID); + break; + case EGR_TAG_PVID: + setbits_le32(&l2rew_reg->port[port_no].port_tag_cfg, + VSC9953_TAG_VID_PVID); + break; + default: + printf("Unknown egress VLAN tag mode for port %d\n", port_no); } +} - return -1; +/* Get egress tag mode for a VSC9953 port */ +static void vsc9953_port_vlan_egress_tag_get(int port_no, + enum egress_vlan_tag *mode) +{ + u32 val; + struct vsc9953_rew_reg *l2rew_reg; + + l2rew_reg = (struct vsc9953_rew_reg *)(VSC9953_OFFSET + + VSC9953_REW_OFFSET); + + val = in_le32(&l2rew_reg->port[port_no].port_tag_cfg); + if (val & VSC9953_TAG_VID_PVID) + *mode = EGR_TAG_PVID; + else + *mode = EGR_TAG_CLASS; } -U_BOOT_CMD(ethsw, 5, 0, do_ethsw, - "vsc9953 l2 switch commands", - "port <port_nr> enable|disable\n" - " - enable/disable an l2 switch port\n" - " port_nr=0..9; use \"all\" for all ports\n" - "ethsw port <port_nr> show\n" - " - show an l2 switch port's configuration\n" - " port_nr=0..9; use \"all\" for all ports\n" -); -#endif /* CONFIG_VSC9953_CMD */ +/* VSC9953 VLAN learning modes */ +enum vlan_learning_mode { + SHARED_VLAN_LEARNING, + PRIVATE_VLAN_LEARNING, +}; + +/* Set VLAN learning mode for VSC9953 */ +static void vsc9953_vlan_learning_set(enum vlan_learning_mode lrn_mode) +{ + struct vsc9953_analyzer *l2ana_reg; + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + switch (lrn_mode) { + case SHARED_VLAN_LEARNING: + setbits_le32(&l2ana_reg->ana.agen_ctrl, VSC9953_FID_MASK_ALL); + break; + case PRIVATE_VLAN_LEARNING: + clrbits_le32(&l2ana_reg->ana.agen_ctrl, VSC9953_FID_MASK_ALL); + break; + default: + printf("Unknown VLAN learn mode\n"); + } +} + +/* Get VLAN learning mode for VSC9953 */ +static int vsc9953_vlan_learning_get(enum vlan_learning_mode *lrn_mode) +{ + u32 val; + struct vsc9953_analyzer *l2ana_reg; + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + val = in_le32(&l2ana_reg->ana.agen_ctrl); + + if (!(val & VSC9953_FID_MASK_ALL)) { + *lrn_mode = PRIVATE_VLAN_LEARNING; + } else if ((val & VSC9953_FID_MASK_ALL) == VSC9953_FID_MASK_ALL) { + *lrn_mode = SHARED_VLAN_LEARNING; + } else { + printf("Unknown VLAN learning mode\n"); + return -EINVAL; + } + + return 0; +} + +/* Enable/disable VLAN ingress filtering on a VSC9953 port */ +static void vsc9953_port_ingress_filtering_set(int port_no, int enabled) +{ + struct vsc9953_analyzer *l2ana_reg; + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + if (enabled) + setbits_le32(&l2ana_reg->ana.vlan_mask, 1 << port_no); + else + clrbits_le32(&l2ana_reg->ana.vlan_mask, 1 << port_no); +} + +/* Return VLAN ingress filtering on a VSC9953 port */ +static int vsc9953_port_ingress_filtering_get(int port_no) +{ + u32 val; + struct vsc9953_analyzer *l2ana_reg; + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + val = in_le32(&l2ana_reg->ana.vlan_mask); + return !!(val & (1 << port_no)); +} + +static int vsc9953_port_status_key_func(struct ethsw_command_def *parsed_cmd) +{ + int i; + u8 enabled; + + /* Last keyword should tell us if we should enable/disable the port */ + if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_enable) + enabled = 1; + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_disable) + enabled = 0; + else + return CMD_RET_USAGE; + + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + vsc9953_port_status_set(parsed_cmd->port, enabled); + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_port_status_set(i, enabled); + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_port_config_key_func(struct ethsw_command_def *parsed_cmd) +{ + int i; + + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + vsc9953_phy_autoneg(parsed_cmd->port); + printf("%8s %8s %8s %8s %8s\n", + "Port", "Status", "Link", "Speed", + "Duplex"); + vsc9953_port_config_show(parsed_cmd->port); + + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_phy_autoneg(i); + printf("%8s %8s %8s %8s %8s\n", + "Port", "Status", "Link", "Speed", "Duplex"); + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_port_config_show(i); + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_port_stats_key_func(struct ethsw_command_def *parsed_cmd) +{ + int i; + + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + vsc9953_port_statistics_show(parsed_cmd->port); + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_port_statistics_show(i); + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_port_stats_clear_key_func(struct ethsw_command_def + *parsed_cmd) +{ + int i; + + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + vsc9953_port_statistics_clear(parsed_cmd->port); + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_port_statistics_clear(i); + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_learn_show_key_func(struct ethsw_command_def *parsed_cmd) +{ + int i; + enum port_learn_mode mode; + + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + if (vsc9953_port_learn_mode_get(parsed_cmd->port, &mode)) + return CMD_RET_FAILURE; + printf("%7s %11s\n", "Port", "Learn mode"); + switch (mode) { + case PORT_LEARN_NONE: + printf("%7d %11s\n", parsed_cmd->port, "disable"); + break; + case PORT_LEARN_AUTO: + printf("%7d %11s\n", parsed_cmd->port, "auto"); + break; + default: + printf("%7d %11s\n", parsed_cmd->port, "-"); + } + } else { + printf("%7s %11s\n", "Port", "Learn mode"); + for (i = 0; i < VSC9953_MAX_PORTS; i++) { + if (vsc9953_port_learn_mode_get(i, &mode)) + continue; + switch (mode) { + case PORT_LEARN_NONE: + printf("%7d %11s\n", i, "disable"); + break; + case PORT_LEARN_AUTO: + printf("%7d %11s\n", i, "auto"); + break; + default: + printf("%7d %11s\n", i, "-"); + } + } + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_learn_set_key_func(struct ethsw_command_def *parsed_cmd) +{ + int i; + enum port_learn_mode mode; + + /* Last keyword should tell us the learn mode */ + if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_auto) + mode = PORT_LEARN_AUTO; + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_disable) + mode = PORT_LEARN_NONE; + else + return CMD_RET_USAGE; + + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + vsc9953_port_learn_mode_set(parsed_cmd->port, mode); + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_port_learn_mode_set(i, mode); + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_fdb_show_key_func(struct ethsw_command_def *parsed_cmd) +{ + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL && + !VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + + if (parsed_cmd->vid != ETHSW_CMD_VLAN_ALL && + !VSC9953_VLAN_CHECK(parsed_cmd->vid)) { + printf("Invalid VID number: %d\n", parsed_cmd->vid); + return CMD_RET_FAILURE; + } + + vsc9953_mac_table_show(parsed_cmd->port, parsed_cmd->vid); + + return CMD_RET_SUCCESS; +} + +static int vsc9953_fdb_flush_key_func(struct ethsw_command_def *parsed_cmd) +{ + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL && + !VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + + if (parsed_cmd->vid != ETHSW_CMD_VLAN_ALL && + !VSC9953_VLAN_CHECK(parsed_cmd->vid)) { + printf("Invalid VID number: %d\n", parsed_cmd->vid); + return CMD_RET_FAILURE; + } + + vsc9953_mac_table_flush(parsed_cmd->port, parsed_cmd->vid); + + return CMD_RET_SUCCESS; +} + +static int vsc9953_fdb_entry_add_key_func(struct ethsw_command_def *parsed_cmd) +{ + int vid; + + /* a port number must be present */ + if (parsed_cmd->port == ETHSW_CMD_PORT_ALL) { + printf("Please specify a port\n"); + return CMD_RET_FAILURE; + } + + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + + /* Use VLAN 1 if VID is not set */ + vid = (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL ? 1 : parsed_cmd->vid); + + if (!VSC9953_VLAN_CHECK(vid)) { + printf("Invalid VID number: %d\n", vid); + return CMD_RET_FAILURE; + } + + if (vsc9953_mac_table_add(parsed_cmd->port, parsed_cmd->ethaddr, vid)) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +static int vsc9953_fdb_entry_del_key_func(struct ethsw_command_def *parsed_cmd) +{ + int vid; + + /* Use VLAN 1 if VID is not set */ + vid = (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL ? 1 : parsed_cmd->vid); + + if (!VSC9953_VLAN_CHECK(vid)) { + printf("Invalid VID number: %d\n", vid); + return CMD_RET_FAILURE; + } + + if (vsc9953_mac_table_del(parsed_cmd->ethaddr, vid)) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +static int vsc9953_pvid_show_key_func(struct ethsw_command_def *parsed_cmd) +{ + int i; + int pvid; + + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + + if (vsc9953_port_vlan_pvid_get(parsed_cmd->port, &pvid)) + return CMD_RET_FAILURE; + printf("%7s %7s\n", "Port", "PVID"); + printf("%7d %7d\n", parsed_cmd->port, pvid); + } else { + printf("%7s %7s\n", "Port", "PVID"); + for (i = 0; i < VSC9953_MAX_PORTS; i++) { + if (vsc9953_port_vlan_pvid_get(i, &pvid)) + continue; + printf("%7d %7d\n", i, pvid); + } + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_pvid_set_key_func(struct ethsw_command_def *parsed_cmd) +{ + /* PVID number should be set in parsed_cmd->vid */ + if (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL) { + printf("Please set a pvid value\n"); + return CMD_RET_FAILURE; + } + + if (!VSC9953_VLAN_CHECK(parsed_cmd->vid)) { + printf("Invalid VID number: %d\n", parsed_cmd->vid); + return CMD_RET_FAILURE; + } + + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + vsc9953_port_vlan_pvid_set(parsed_cmd->port, parsed_cmd->vid); + } else { + vsc9953_port_all_vlan_pvid_set(parsed_cmd->vid); + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_vlan_show_key_func(struct ethsw_command_def *parsed_cmd) +{ + int i; + + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + vsc9953_vlan_membership_show(parsed_cmd->port); + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_vlan_membership_show(i); + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_vlan_set_key_func(struct ethsw_command_def *parsed_cmd) +{ + int i; + int add; + + /* VLAN should be set in parsed_cmd->vid */ + if (parsed_cmd->vid == ETHSW_CMD_VLAN_ALL) { + printf("Please set a vlan value\n"); + return CMD_RET_FAILURE; + } + + if (!VSC9953_VLAN_CHECK(parsed_cmd->vid)) { + printf("Invalid VID number: %d\n", parsed_cmd->vid); + return CMD_RET_FAILURE; + } + + /* keywords add/delete should be the last but one in array */ + if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] == + ethsw_id_add) + add = 1; + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 2] == + ethsw_id_del) + add = 0; + else + return CMD_RET_USAGE; + + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + vsc9953_vlan_table_membership_set(parsed_cmd->vid, + parsed_cmd->port, add); + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_vlan_table_membership_set(parsed_cmd->vid, i, + add); + } + + return CMD_RET_SUCCESS; +} +static int vsc9953_port_untag_show_key_func( + struct ethsw_command_def *parsed_cmd) +{ + int i; + + printf("%7s\t%17s\n", "Port", "Untag"); + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + vsc9953_port_vlan_egr_untag_show(parsed_cmd->port); + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_port_vlan_egr_untag_show(i); + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_port_untag_set_key_func(struct ethsw_command_def *parsed_cmd) +{ + int i; + enum egress_untag_mode mode; + + /* keywords for the untagged mode are the last in the array */ + if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_all) + mode = EGRESS_UNTAG_ALL; + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_none) + mode = EGRESS_UNTAG_NONE; + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_pvid) + mode = EGRESS_UNTAG_PVID_AND_ZERO; + else + return CMD_RET_USAGE; + + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + vsc9953_port_vlan_egr_untag_set(parsed_cmd->port, mode); + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_port_vlan_egr_untag_set(i, mode); + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_egr_vlan_tag_show_key_func( + struct ethsw_command_def *parsed_cmd) +{ + int i; + enum egress_vlan_tag mode; + + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + vsc9953_port_vlan_egress_tag_get(parsed_cmd->port, &mode); + printf("%7s\t%12s\n", "Port", "Egress VID"); + printf("%7d\t", parsed_cmd->port); + switch (mode) { + case EGR_TAG_CLASS: + printf("%12s\n", "classified"); + break; + case EGR_TAG_PVID: + printf("%12s\n", "pvid"); + break; + default: + printf("%12s\n", "-"); + } + } else { + printf("%7s\t%12s\n", "Port", "Egress VID"); + for (i = 0; i < VSC9953_MAX_PORTS; i++) { + vsc9953_port_vlan_egress_tag_get(i, &mode); + switch (mode) { + case EGR_TAG_CLASS: + printf("%7d\t%12s\n", i, "classified"); + break; + case EGR_TAG_PVID: + printf("%7d\t%12s\n", i, "pvid"); + break; + default: + printf("%7d\t%12s\n", i, "-"); + } + } + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_egr_vlan_tag_set_key_func( + struct ethsw_command_def *parsed_cmd) +{ + int i; + enum egress_vlan_tag mode; + + /* keywords for the egress vlan tag mode are the last in the array */ + if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_pvid) + mode = EGR_TAG_PVID; + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_classified) + mode = EGR_TAG_CLASS; + else + return CMD_RET_USAGE; + + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + vsc9953_port_vlan_egress_tag_set(parsed_cmd->port, mode); + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_port_vlan_egress_tag_set(i, mode); + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_vlan_learn_show_key_func( + struct ethsw_command_def *parsed_cmd) +{ + int rc; + enum vlan_learning_mode mode; + + rc = vsc9953_vlan_learning_get(&mode); + if (rc) + return CMD_RET_FAILURE; + + switch (mode) { + case SHARED_VLAN_LEARNING: + printf("VLAN learning mode: shared\n"); + break; + case PRIVATE_VLAN_LEARNING: + printf("VLAN learning mode: private\n"); + break; + default: + printf("Unknown VLAN learning mode\n"); + rc = CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_vlan_learn_set_key_func(struct ethsw_command_def *parsed_cmd) +{ + enum vlan_learning_mode mode; + + /* keywords for shared/private are the last in the array */ + if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_shared) + mode = SHARED_VLAN_LEARNING; + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_private) + mode = PRIVATE_VLAN_LEARNING; + else + return CMD_RET_USAGE; + + vsc9953_vlan_learning_set(mode); + + return CMD_RET_SUCCESS; +} + +static int vsc9953_ingr_fltr_show_key_func(struct ethsw_command_def *parsed_cmd) +{ + int i; + int enabled; + + printf("%7s\t%18s\n", "Port", "Ingress filtering"); + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + enabled = vsc9953_port_ingress_filtering_get(parsed_cmd->port); + printf("%7d\t%18s\n", parsed_cmd->port, enabled ? "enable" : + "disable"); + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) { + enabled = vsc9953_port_ingress_filtering_get(i); + printf("%7d\t%18s\n", parsed_cmd->port, enabled ? + "enable" : + "disable"); + } + } + + return CMD_RET_SUCCESS; +} + +static int vsc9953_ingr_fltr_set_key_func(struct ethsw_command_def *parsed_cmd) +{ + int i; + int enable; + + /* keywords for enabling/disabling ingress filtering + * are the last in the array + */ + if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_enable) + enable = 1; + else if (parsed_cmd->cmd_to_keywords[parsed_cmd->cmd_keywords_nr - 1] == + ethsw_id_disable) + enable = 0; + else + return CMD_RET_USAGE; + + if (parsed_cmd->port != ETHSW_CMD_PORT_ALL) { + if (!VSC9953_PORT_CHECK(parsed_cmd->port)) { + printf("Invalid port number: %d\n", parsed_cmd->port); + return CMD_RET_FAILURE; + } + vsc9953_port_ingress_filtering_set(parsed_cmd->port, enable); + } else { + for (i = 0; i < VSC9953_MAX_PORTS; i++) + vsc9953_port_ingress_filtering_set(i, enable); + } + + return CMD_RET_SUCCESS; +} + +static struct ethsw_command_func vsc9953_cmd_func = { + .ethsw_name = "L2 Switch VSC9953", + .port_enable = &vsc9953_port_status_key_func, + .port_disable = &vsc9953_port_status_key_func, + .port_show = &vsc9953_port_config_key_func, + .port_stats = &vsc9953_port_stats_key_func, + .port_stats_clear = &vsc9953_port_stats_clear_key_func, + .port_learn = &vsc9953_learn_set_key_func, + .port_learn_show = &vsc9953_learn_show_key_func, + .fdb_show = &vsc9953_fdb_show_key_func, + .fdb_flush = &vsc9953_fdb_flush_key_func, + .fdb_entry_add = &vsc9953_fdb_entry_add_key_func, + .fdb_entry_del = &vsc9953_fdb_entry_del_key_func, + .pvid_show = &vsc9953_pvid_show_key_func, + .pvid_set = &vsc9953_pvid_set_key_func, + .vlan_show = &vsc9953_vlan_show_key_func, + .vlan_set = &vsc9953_vlan_set_key_func, + .port_untag_show = &vsc9953_port_untag_show_key_func, + .port_untag_set = &vsc9953_port_untag_set_key_func, + .port_egr_vlan_show = &vsc9953_egr_vlan_tag_show_key_func, + .port_egr_vlan_set = &vsc9953_egr_vlan_tag_set_key_func, + .vlan_learn_show = &vsc9953_vlan_learn_show_key_func, + .vlan_learn_set = &vsc9953_vlan_learn_set_key_func, + .port_ingr_filt_show = &vsc9953_ingr_fltr_show_key_func, + .port_ingr_filt_set = &vsc9953_ingr_fltr_set_key_func +}; + +#endif /* CONFIG_CMD_ETHSW */ + +/***************************************************************************** +At startup, the default configuration would be: + - HW learning enabled on all ports; (HW default) + - All ports are in VLAN 1; + - All ports are VLAN aware; + - All ports have POP_COUNT 1; + - All ports have PVID 1; + - All ports have TPID 0x8100; (HW default) + - All ports tag frames classified to all VLANs that are not PVID; +*****************************************************************************/ +void vsc9953_default_configuration(void) +{ + int i; + + for (i = 0; i < VSC9953_MAX_VLAN; i++) + vsc9953_vlan_table_membership_all_set(i, 0); + vsc9953_port_all_vlan_aware_set(1); + vsc9953_port_all_vlan_pvid_set(1); + vsc9953_port_all_vlan_poncnt_set(1); + vsc9953_vlan_table_membership_all_set(1, 1); + vsc9953_vlan_ingr_fltr_learn_drop(1); + vsc9953_port_all_vlan_egress_untagged_set(EGRESS_UNTAG_PVID_AND_ZERO); +} + +void vsc9953_init(bd_t *bis) +{ + u32 i; + u32 hdx_cfg = 0; + u32 phy_addr = 0; + int timeout; + struct vsc9953_system_reg *l2sys_reg; + struct vsc9953_qsys_reg *l2qsys_reg; + struct vsc9953_dev_gmii *l2dev_gmii_reg; + struct vsc9953_analyzer *l2ana_reg; + struct vsc9953_devcpu_gcb *l2dev_gcb; + + l2dev_gmii_reg = (struct vsc9953_dev_gmii *)(VSC9953_OFFSET + + VSC9953_DEV_GMII_OFFSET); + + l2ana_reg = (struct vsc9953_analyzer *)(VSC9953_OFFSET + + VSC9953_ANA_OFFSET); + + l2sys_reg = (struct vsc9953_system_reg *)(VSC9953_OFFSET + + VSC9953_SYS_OFFSET); + + l2qsys_reg = (struct vsc9953_qsys_reg *)(VSC9953_OFFSET + + VSC9953_QSYS_OFFSET); + + l2dev_gcb = (struct vsc9953_devcpu_gcb *)(VSC9953_OFFSET + + VSC9953_DEVCPU_GCB); + + out_le32(&l2dev_gcb->chip_regs.soft_rst, + VSC9953_SOFT_SWC_RST_ENA); + timeout = 50000; + while ((in_le32(&l2dev_gcb->chip_regs.soft_rst) & + VSC9953_SOFT_SWC_RST_ENA) && --timeout) + udelay(1); /* busy wait for vsc9953 soft reset */ + if (timeout == 0) + debug("Timeout waiting for VSC9953 to reset\n"); + + out_le32(&l2sys_reg->sys.reset_cfg, VSC9953_MEM_ENABLE | + VSC9953_MEM_INIT); + + timeout = 50000; + while ((in_le32(&l2sys_reg->sys.reset_cfg) & + VSC9953_MEM_INIT) && --timeout) + udelay(1); /* busy wait for vsc9953 memory init */ + if (timeout == 0) + debug("Timeout waiting for VSC9953 memory to initialize\n"); + + out_le32(&l2sys_reg->sys.reset_cfg, (in_le32(&l2sys_reg->sys.reset_cfg) + | VSC9953_CORE_ENABLE)); + + /* VSC9953 Setting to be done once only */ + out_le32(&l2qsys_reg->sys.ext_cpu_cfg, 0x00000b00); + + for (i = 0; i < VSC9953_MAX_PORTS; i++) { + if (vsc9953_port_init(i)) + printf("Failed to initialize l2switch port %d\n", i); + + /* Enable VSC9953 GMII Ports Port ID 0 - 7 */ + if (VSC9953_INTERNAL_PORT_CHECK(i)) { + out_le32(&l2ana_reg->pfc[i].pfc_cfg, + VSC9953_PFC_FC_QSGMII); + out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i], + VSC9953_MAC_FC_CFG_QSGMII); + } else { + out_le32(&l2ana_reg->pfc[i].pfc_cfg, + VSC9953_PFC_FC); + out_le32(&l2sys_reg->pause_cfg.mac_fc_cfg[i], + VSC9953_MAC_FC_CFG); + } + out_le32(&l2dev_gmii_reg->port_mode.clock_cfg, + VSC9953_CLOCK_CFG); + out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ena_cfg, + VSC9953_MAC_ENA_CFG); + out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_mode_cfg, + VSC9953_MAC_MODE_CFG); + out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_ifg_cfg, + VSC9953_MAC_IFG_CFG); + /* mac_hdx_cfg varies with port id*/ + hdx_cfg = VSC9953_MAC_HDX_CFG | (i << 16); + out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_hdx_cfg, hdx_cfg); + out_le32(&l2sys_reg->sys.front_port_mode[i], + VSC9953_FRONT_PORT_MODE); + setbits_le32(&l2qsys_reg->sys.switch_port_mode[i], + VSC9953_PORT_ENA); + out_le32(&l2dev_gmii_reg->mac_cfg_status.mac_maxlen_cfg, + VSC9953_MAC_MAX_LEN); + out_le32(&l2sys_reg->pause_cfg.pause_cfg[i], + VSC9953_PAUSE_CFG); + /* WAIT FOR 2 us*/ + udelay(2); + + l2dev_gmii_reg = (struct vsc9953_dev_gmii *)( + (char *)l2dev_gmii_reg + + T1040_SWITCH_GMII_DEV_OFFSET); + + /* Initialize Lynx PHY Wrappers */ + phy_addr = 0; + if (vsc9953_l2sw.port[i].enet_if == + PHY_INTERFACE_MODE_QSGMII) + phy_addr = (i + 0x4) & 0x1F; + else if (vsc9953_l2sw.port[i].enet_if == + PHY_INTERFACE_MODE_SGMII) + phy_addr = (i + 1) & 0x1F; + + if (phy_addr) { + /* SGMII IF mode + AN enable */ + vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, + 0x14, PHY_SGMII_IF_MODE_AN | + PHY_SGMII_IF_MODE_SGMII); + /* Dev ability according to SGMII specification */ + vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, + 0x4, PHY_SGMII_DEV_ABILITY_SGMII); + /* Adjust link timer for SGMII + * 1.6 ms in units of 8 ns = 2 * 10^5 = 0x30d40 + */ + vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, + 0x13, 0x0003); + vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, + 0x12, 0x0d40); + /* Restart AN */ + vsc9953_mdio_write(&l2dev_gcb->mii_mng[0], phy_addr, + 0x0, PHY_SGMII_CR_DEF_VAL | + PHY_SGMII_CR_RESET_AN); + + timeout = 50000; + while ((vsc9953_mdio_read(&l2dev_gcb->mii_mng[0], + phy_addr, 0x01) & 0x0020) && --timeout) + udelay(1); /* wait for AN to complete */ + if (timeout == 0) + debug("Timeout waiting for AN to complete\n"); + } + } + + vsc9953_default_configuration(); + +#ifdef CONFIG_CMD_ETHSW + if (ethsw_define_functions(&vsc9953_cmd_func) < 0) + debug("Unable to use \"ethsw\" commands\n"); +#endif + + printf("VSC9953 L2 switch initialized\n"); + return; +} diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index ea70853da2..0756bbe8f1 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -238,7 +238,7 @@ int dm_pci_write_config(struct udevice *dev, int offset, unsigned long value, { struct udevice *bus; - for (bus = dev; device_get_uclass_id(bus->parent) == UCLASS_PCI;) + for (bus = dev; device_is_on_pci_bus(bus);) bus = bus->parent; return pci_bus_write_config(bus, pci_get_bdf(dev), offset, value, size); } @@ -303,7 +303,7 @@ int dm_pci_read_config(struct udevice *dev, int offset, unsigned long *valuep, { struct udevice *bus; - for (bus = dev; device_get_uclass_id(bus->parent) == UCLASS_PCI;) + for (bus = dev; device_is_on_pci_bus(bus);) bus = bus->parent; return pci_bus_read_config(bus, pci_get_bdf(dev), offset, valuep, size); diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index 41d5447f12..79f27c744b 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -185,6 +185,7 @@ void pciauto_setup_device(struct pci_controller *hose, #ifndef CONFIG_PCI_ENUM_ONLY /* Configure the expansion ROM address */ pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type); + header_type &= 0x7f; if (header_type != PCI_HEADER_TYPE_CARDBUS) { rom_addr = (header_type == PCI_HEADER_TYPE_NORMAL) ? PCI_ROM_ADDRESS : PCI_ROM_ADDRESS1; diff --git a/drivers/pci/pcie_imx.c b/drivers/pci/pcie_imx.c index ca485ba90c..1568f20c1a 100644 --- a/drivers/pci/pcie_imx.c +++ b/drivers/pci/pcie_imx.c @@ -495,7 +495,7 @@ __weak int imx6_pcie_toggle_reset(void) * * The PCIe #PERST reset line _MUST_ be connected, otherwise your * design does not conform to the specification. You must wait at - * least 20 mS after de-asserting the #PERST so the EP device can + * least 20 ms after de-asserting the #PERST so the EP device can * do self-initialisation. * * In case your #PERST pin is connected to a plain GPIO pin of the @@ -506,7 +506,7 @@ __weak int imx6_pcie_toggle_reset(void) * In case your #PERST toggling logic is more complex, for example * connected via CPLD or somesuch, you can override this function * in your board file and implement reset logic as needed. You must - * not forget to wait at least 20 mS after de-asserting #PERST in + * not forget to wait at least 20 ms after de-asserting #PERST in * this case either though. * * In case your #PERST line of the PCIe EP device is not connected @@ -538,7 +538,7 @@ static int imx6_pcie_deassert_core_reset(void) /* * Wait for the clock to settle a bit, when the clock are sourced - * from the CPU, we need about 30mS to settle. + * from the CPU, we need about 30 ms to settle. */ mdelay(50); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index b8146df99b..3b6e3b7060 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -124,4 +124,6 @@ config PINCTRL_SANDBOX endif +source "drivers/pinctrl/uniphier/Kconfig" + endmenu diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f537df4e88..e56a17f966 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -3,3 +3,5 @@ obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o + +obj-$(CONFIG_ARCH_UNIPHIER) += uniphier/ diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c index 58001ef572..b5fdcd12a8 100644 --- a/drivers/pinctrl/pinctrl-uclass.c +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -11,7 +11,6 @@ #include <dm/device.h> #include <dm/lists.h> #include <dm/pinctrl.h> -#include <dm/root.h> #include <dm/uclass.h> DECLARE_GLOBAL_DATA_PTR; @@ -160,8 +159,7 @@ static int pinctrl_select_state_full(struct udevice *dev, const char *statename) static int pinconfig_post_bind(struct udevice *dev) { - /* Scan the bus for devices */ - return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); + return 0; } #endif @@ -249,10 +247,15 @@ static int pinctrl_post_bind(struct udevice *dev) } /* - * The pinctrl driver child nodes should be bound so that peripheral - * devices can easily search in parent devices during later DT-parsing. + * If set_state callback is set, we assume this pinctrl driver is the + * full implementation. In this case, its child nodes should be bound + * so that peripheral devices can easily search in parent devices + * during later DT-parsing. */ - return pinconfig_post_bind(dev); + if (ops->set_state) + return pinconfig_post_bind(dev); + + return 0; } UCLASS_DRIVER(pinctrl) = { diff --git a/drivers/pinctrl/rockchip/pinctrl_rk3288.c b/drivers/pinctrl/rockchip/pinctrl_rk3288.c index 5205498b36..c432a008e7 100644 --- a/drivers/pinctrl/rockchip/pinctrl_rk3288.c +++ b/drivers/pinctrl/rockchip/pinctrl_rk3288.c @@ -17,6 +17,7 @@ #include <asm/arch/periph.h> #include <asm/arch/pmu_rk3288.h> #include <dm/pinctrl.h> +#include <dm/root.h> DECLARE_GLOBAL_DATA_PTR; @@ -415,6 +416,12 @@ static struct pinctrl_ops rk3288_pinctrl_ops = { .get_periph_id = rk3288_pinctrl_get_periph_id, }; +static int rk3288_pinctrl_bind(struct udevice *dev) +{ + /* scan child GPIO banks */ + return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false); +} + static int rk3288_pinctrl_probe(struct udevice *dev) { struct rk3288_pinctrl_priv *priv = dev_get_priv(dev); @@ -437,5 +444,6 @@ U_BOOT_DRIVER(pinctrl_rk3288) = { .of_match = rk3288_pinctrl_ids, .priv_auto_alloc_size = sizeof(struct rk3288_pinctrl_priv), .ops = &rk3288_pinctrl_ops, + .bind = rk3288_pinctrl_bind, .probe = rk3288_pinctrl_probe, }; diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig new file mode 100644 index 0000000000..2ff616e946 --- /dev/null +++ b/drivers/pinctrl/uniphier/Kconfig @@ -0,0 +1,42 @@ +if ARCH_UNIPHIER + +config PINCTRL_UNIPHIER_CORE + bool + +config PINCTRL_UNIPHIER_PH1_LD4 + bool "UniPhier PH1-LD4 SoC pinctrl driver" + depends on ARCH_UNIPHIER_PH1_LD4 + default y + select PINCTRL_UNIPHIER_CORE + +config PINCTRL_UNIPHIER_PH1_PRO4 + bool "UniPhier PH1-Pro4 SoC pinctrl driver" + depends on ARCH_UNIPHIER_PH1_PRO4 + default y + select PINCTRL_UNIPHIER_CORE + +config PINCTRL_UNIPHIER_PH1_SLD8 + bool "UniPhier PH1-sLD8 SoC pinctrl driver" + depends on ARCH_UNIPHIER_PH1_SLD8 + default y + select PINCTRL_UNIPHIER_CORE + +config PINCTRL_UNIPHIER_PH1_PRO5 + bool "UniPhier PH1-Pro5 SoC pinctrl driver" + depends on ARCH_UNIPHIER_PH1_PRO5 + default y + select PINCTRL_UNIPHIER_CORE + +config PINCTRL_UNIPHIER_PROXSTREAM2 + bool "UniPhier ProXstream2 SoC pinctrl driver" + depends on ARCH_UNIPHIER_PROXSTREAM2 + default y + select PINCTRL_UNIPHIER_CORE + +config PINCTRL_UNIPHIER_PH1_LD6B + bool "UniPhier PH1-LD6b SoC pinctrl driver" + depends on ARCH_UNIPHIER_PH1_LD6B + default y + select PINCTRL_UNIPHIER_CORE + +endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile new file mode 100644 index 0000000000..e215b10972 --- /dev/null +++ b/drivers/pinctrl/uniphier/Makefile @@ -0,0 +1,8 @@ +obj-$(CONFIG_PINCTRL_UNIPHIER_CORE) += pinctrl-uniphier-core.o + +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD4) += pinctrl-ph1-ld4.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO4) += pinctrl-ph1-pro4.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_SLD8) += pinctrl-ph1-sld8.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO5) += pinctrl-ph1-pro5.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PROXSTREAM2) += pinctrl-proxstream2.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD6B) += pinctrl-ph1-ld6b.o diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c b/drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c new file mode 100644 index 0000000000..b3d47f0915 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <dm/device.h> +#include <dm/pinctrl.h> + +#include "pinctrl-uniphier.h" + +static const struct uniphier_pinctrl_pin ph1_ld4_pins[] = { + UNIPHIER_PINCTRL_PIN(53, 0), + UNIPHIER_PINCTRL_PIN(54, 0), + UNIPHIER_PINCTRL_PIN(55, 0), + UNIPHIER_PINCTRL_PIN(56, 0), + UNIPHIER_PINCTRL_PIN(67, 0), + UNIPHIER_PINCTRL_PIN(68, 0), + UNIPHIER_PINCTRL_PIN(69, 0), + UNIPHIER_PINCTRL_PIN(70, 0), + UNIPHIER_PINCTRL_PIN(85, 0), + UNIPHIER_PINCTRL_PIN(88, 0), + UNIPHIER_PINCTRL_PIN(156, 0), +}; + +static const unsigned emmc_pins[] = {21, 22, 23, 24, 25, 26, 27}; +static const unsigned emmc_muxvals[] = {0, 1, 1, 1, 1, 1, 1}; +static const unsigned emmc_dat8_pins[] = {28, 29, 30, 31}; +static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1}; +static const unsigned i2c0_pins[] = {102, 103}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {104, 105}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {108, 109}; +static const unsigned i2c2_muxvals[] = {2, 2}; +static const unsigned i2c3_pins[] = {108, 109}; +static const unsigned i2c3_muxvals[] = {3, 3}; +static const unsigned nand_pins[] = {24, 25, 26, 27, 28, 29, 30, 31, 158, 159, + 160, 161, 162, 163, 164}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {22, 23}; +static const unsigned nand_cs1_muxvals[] = {0, 0}; +static const unsigned sd_pins[] = {44, 45, 46, 47, 48, 49, 50, 51, 52}; +static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const unsigned uart0_pins[] = {85, 88}; +static const unsigned uart0_muxvals[] = {1, 1}; +static const unsigned uart1_pins[] = {155, 156}; +static const unsigned uart1_muxvals[] = {13, 13}; +static const unsigned uart1b_pins[] = {69, 70}; +static const unsigned uart1b_muxvals[] = {23, 23}; +static const unsigned uart2_pins[] = {128, 129}; +static const unsigned uart2_muxvals[] = {13, 13}; +static const unsigned uart3_pins[] = {110, 111}; +static const unsigned uart3_muxvals[] = {1, 1}; +static const unsigned usb0_pins[] = {53, 54}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {55, 56}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {155, 156}; +static const unsigned usb2_muxvals[] = {4, 4}; +static const unsigned usb2b_pins[] = {67, 68}; +static const unsigned usb2b_muxvals[] = {23, 23}; + +static const struct uniphier_pinctrl_group ph1_ld4_groups[] = { + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(sd), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart1b), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP(usb2b), +}; + +static const char * const ph1_ld4_functions[] = { + "emmc", + "i2c0", + "i2c1", + "i2c2", + "i2c3", + "nand", + "sd", + "uart0", + "uart1", + "uart2", + "uart3", + "usb0", + "usb1", + "usb2", +}; + +static struct uniphier_pinctrl_socdata ph1_ld4_pinctrl_socdata = { + .pins = ph1_ld4_pins, + .pins_count = ARRAY_SIZE(ph1_ld4_pins), + .groups = ph1_ld4_groups, + .groups_count = ARRAY_SIZE(ph1_ld4_groups), + .functions = ph1_ld4_functions, + .functions_count = ARRAY_SIZE(ph1_ld4_functions), + .mux_bits = 8, + .reg_stride = 4, + .load_pinctrl = false, +}; + +static int ph1_ld4_pinctrl_probe(struct udevice *dev) +{ + return uniphier_pinctrl_probe(dev, &ph1_ld4_pinctrl_socdata); +} + +static const struct udevice_id ph1_ld4_pinctrl_match[] = { + { .compatible = "socionext,ph1-ld4-pinctrl" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(ph1_ld4_pinctrl) = { + .name = "ph1-ld4-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(ph1_ld4_pinctrl_match), + .probe = ph1_ld4_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .priv_auto_alloc_size = sizeof(struct uniphier_pinctrl_priv), + .ops = &uniphier_pinctrl_ops, +}; diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c b/drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c new file mode 100644 index 0000000000..8703a215e4 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <dm/device.h> +#include <dm/pinctrl.h> + +#include "pinctrl-uniphier.h" + +static const struct uniphier_pinctrl_pin ph1_ld6b_pins[] = { + UNIPHIER_PINCTRL_PIN(113, 0), + UNIPHIER_PINCTRL_PIN(114, 0), + UNIPHIER_PINCTRL_PIN(115, 0), + UNIPHIER_PINCTRL_PIN(116, 0), + UNIPHIER_PINCTRL_PIN(217, 0), + UNIPHIER_PINCTRL_PIN(218, 0), + UNIPHIER_PINCTRL_PIN(219, 0), + UNIPHIER_PINCTRL_PIN(220, 0), +}; + +static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42}; +static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1}; +static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46}; +static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1}; +static const unsigned i2c0_pins[] = {109, 110}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {111, 112}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {115, 116}; +static const unsigned i2c2_muxvals[] = {1, 1}; +static const unsigned i2c3_pins[] = {118, 119}; +static const unsigned i2c3_muxvals[] = {1, 1}; +static const unsigned nand_pins[] = {30, 31, 32, 33, 34, 35, 36, 39, 40, 41, + 42, 43, 44, 45, 46}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {37, 38}; +static const unsigned nand_cs1_muxvals[] = {0, 0}; +static const unsigned sd_pins[] = {47, 48, 49, 50, 51, 52, 53, 54, 55}; +static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const unsigned uart0_pins[] = {135, 136}; +static const unsigned uart0_muxvals[] = {3, 3}; +static const unsigned uart0b_pins[] = {11, 12}; +static const unsigned uart0b_muxvals[] = {2, 2}; +static const unsigned uart1_pins[] = {115, 116}; +static const unsigned uart1_muxvals[] = {0, 0}; +static const unsigned uart1b_pins[] = {113, 114}; +static const unsigned uart1b_muxvals[] = {1, 1}; +static const unsigned uart2_pins[] = {113, 114}; +static const unsigned uart2_muxvals[] = {2, 2}; +static const unsigned uart2b_pins[] = {86, 87}; +static const unsigned uart2b_muxvals[] = {1, 1}; +static const unsigned usb0_pins[] = {56, 57}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {58, 59}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {60, 61}; +static const unsigned usb2_muxvals[] = {0, 0}; +static const unsigned usb3_pins[] = {62, 63}; +static const unsigned usb3_muxvals[] = {0, 0}; + +static const struct uniphier_pinctrl_group ph1_ld6b_groups[] = { + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(sd), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart0b), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart1b), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart2b), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP(usb3), +}; + +static const char * const ph1_ld6b_functions[] = { + "emmc", + "i2c0", + "i2c1", + "i2c2", + "i2c3", + "nand", + "sd", + "uart0", + "uart1", + "uart2", + "usb0", + "usb1", + "usb2", + "usb3", +}; + +static struct uniphier_pinctrl_socdata ph1_ld6b_pinctrl_socdata = { + .pins = ph1_ld6b_pins, + .pins_count = ARRAY_SIZE(ph1_ld6b_pins), + .groups = ph1_ld6b_groups, + .groups_count = ARRAY_SIZE(ph1_ld6b_groups), + .functions = ph1_ld6b_functions, + .functions_count = ARRAY_SIZE(ph1_ld6b_functions), + .mux_bits = 8, + .reg_stride = 4, + .load_pinctrl = false, +}; + +static int ph1_ld6b_pinctrl_probe(struct udevice *dev) +{ + return uniphier_pinctrl_probe(dev, &ph1_ld6b_pinctrl_socdata); +} + +static const struct udevice_id ph1_ld6b_pinctrl_match[] = { + { .compatible = "socionext,ph1-ld6b-pinctrl" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(ph1_ld6b_pinctrl) = { + .name = "ph1-ld6b-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(ph1_ld6b_pinctrl_match), + .probe = ph1_ld6b_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .priv_auto_alloc_size = sizeof(struct uniphier_pinctrl_priv), + .ops = &uniphier_pinctrl_ops, +}; diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c b/drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c new file mode 100644 index 0000000000..b3eaf138f7 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <dm/device.h> +#include <dm/pinctrl.h> + +#include "pinctrl-uniphier.h" + +static const struct uniphier_pinctrl_pin ph1_pro4_pins[] = { +}; + +static const unsigned emmc_pins[] = {40, 41, 42, 43, 51, 52, 53}; +static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1}; +static const unsigned emmc_dat8_pins[] = {44, 45, 46, 47}; +static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1}; +static const unsigned i2c0_pins[] = {142, 143}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {144, 145}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {146, 147}; +static const unsigned i2c2_muxvals[] = {0, 0}; +static const unsigned i2c3_pins[] = {148, 149}; +static const unsigned i2c3_muxvals[] = {0, 0}; +static const unsigned i2c6_pins[] = {308, 309}; +static const unsigned i2c6_muxvals[] = {6, 6}; +static const unsigned nand_pins[] = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {131, 132}; +static const unsigned nand_cs1_muxvals[] = {1, 1}; +static const unsigned sd_pins[] = {150, 151, 152, 153, 154, 155, 156, 157, 158}; +static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const unsigned sd1_pins[] = {319, 320, 321, 322, 323, 324, 325, 326, + 327}; +static const unsigned sd1_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const unsigned uart0_pins[] = {127, 128}; +static const unsigned uart0_muxvals[] = {0, 0}; +static const unsigned uart1_pins[] = {129, 130}; +static const unsigned uart1_muxvals[] = {0, 0}; +static const unsigned uart2_pins[] = {131, 132}; +static const unsigned uart2_muxvals[] = {0, 0}; +static const unsigned uart3_pins[] = {88, 89}; +static const unsigned uart3_muxvals[] = {2, 2}; +static const unsigned usb0_pins[] = {180, 181}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {182, 183}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {184, 185}; +static const unsigned usb2_muxvals[] = {0, 0}; +static const unsigned usb3_pins[] = {186, 187}; +static const unsigned usb3_muxvals[] = {0, 0}; + +static const struct uniphier_pinctrl_group ph1_pro4_groups[] = { + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(i2c6), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(sd), + UNIPHIER_PINCTRL_GROUP(sd1), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP(usb3), +}; + +static const char * const ph1_pro4_functions[] = { + "emmc", + "i2c0", + "i2c1", + "i2c2", + "i2c3", + "i2c6", + "nand", + "sd", + "sd1", + "uart0", + "uart1", + "uart2", + "uart3", + "usb0", + "usb1", + "usb2", + "usb3", +}; + +static struct uniphier_pinctrl_socdata ph1_pro4_pinctrl_socdata = { + .pins = ph1_pro4_pins, + .pins_count = ARRAY_SIZE(ph1_pro4_pins), + .groups = ph1_pro4_groups, + .groups_count = ARRAY_SIZE(ph1_pro4_groups), + .functions = ph1_pro4_functions, + .functions_count = ARRAY_SIZE(ph1_pro4_functions), + .mux_bits = 4, + .reg_stride = 8, + .load_pinctrl = true, +}; + +static int ph1_pro4_pinctrl_probe(struct udevice *dev) +{ + return uniphier_pinctrl_probe(dev, &ph1_pro4_pinctrl_socdata); +} + +static const struct udevice_id ph1_pro4_pinctrl_match[] = { + { .compatible = "socionext,ph1-pro4-pinctrl" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(ph1_pro4_pinctrl) = { + .name = "ph1-pro4-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(ph1_pro4_pinctrl_match), + .probe = ph1_pro4_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .priv_auto_alloc_size = sizeof(struct uniphier_pinctrl_priv), + .ops = &uniphier_pinctrl_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c b/drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c new file mode 100644 index 0000000000..3749250066 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <dm/device.h> +#include <dm/pinctrl.h> + +#include "pinctrl-uniphier.h" + +static const struct uniphier_pinctrl_pin ph1_pro5_pins[] = { + UNIPHIER_PINCTRL_PIN(47, 0), + UNIPHIER_PINCTRL_PIN(48, 0), + UNIPHIER_PINCTRL_PIN(49, 0), + UNIPHIER_PINCTRL_PIN(50, 0), + UNIPHIER_PINCTRL_PIN(53, 0), + UNIPHIER_PINCTRL_PIN(54, 0), + UNIPHIER_PINCTRL_PIN(87, 0), + UNIPHIER_PINCTRL_PIN(88, 0), + UNIPHIER_PINCTRL_PIN(101, 0), + UNIPHIER_PINCTRL_PIN(102, 0), +}; + +static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42}; +static const unsigned emmc_muxvals[] = {0, 0, 0, 0, 0, 0, 0}; +static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46}; +static const unsigned emmc_dat8_muxvals[] = {0, 0, 0, 0}; +static const unsigned i2c0_pins[] = {112, 113}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {114, 115}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {116, 117}; +static const unsigned i2c2_muxvals[] = {0, 0}; +static const unsigned i2c3_pins[] = {118, 119}; +static const unsigned i2c3_muxvals[] = {0, 0}; +static const unsigned i2c5_pins[] = {87, 88}; +static const unsigned i2c5_muxvals[] = {2, 2}; +static const unsigned i2c5b_pins[] = {196, 197}; +static const unsigned i2c5b_muxvals[] = {2, 2}; +static const unsigned i2c5c_pins[] = {215, 216}; +static const unsigned i2c5c_muxvals[] = {2, 2}; +static const unsigned i2c6_pins[] = {101, 102}; +static const unsigned i2c6_muxvals[] = {2, 2}; +static const unsigned nand_pins[] = {19, 20, 21, 22, 23, 24, 25, 28, 29, 30, + 31, 32, 33, 34, 35}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {26, 27}; +static const unsigned nand_cs1_muxvals[] = {0, 0}; +static const unsigned sd_pins[] = {250, 251, 252, 253, 254, 255, 256, 257, 258}; +static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const unsigned uart0_pins[] = {47, 48}; +static const unsigned uart0_muxvals[] = {0, 0}; +static const unsigned uart0b_pins[] = {227, 228}; +static const unsigned uart0b_muxvals[] = {3, 3}; +static const unsigned uart1_pins[] = {49, 50}; +static const unsigned uart1_muxvals[] = {0, 0}; +static const unsigned uart2_pins[] = {51, 52}; +static const unsigned uart2_muxvals[] = {0, 0}; +static const unsigned uart3_pins[] = {53, 54}; +static const unsigned uart3_muxvals[] = {0, 0}; +static const unsigned usb0_pins[] = {124, 125}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {126, 127}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {128, 129}; +static const unsigned usb2_muxvals[] = {0, 0}; + +static const struct uniphier_pinctrl_group ph1_pro5_groups[] = { + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(i2c5), + UNIPHIER_PINCTRL_GROUP(i2c5b), + UNIPHIER_PINCTRL_GROUP(i2c5c), + UNIPHIER_PINCTRL_GROUP(i2c6), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(sd), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart0b), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), +}; + +static const char * const ph1_pro5_functions[] = { + "emmc", + "i2c0", + "i2c1", + "i2c2", + "i2c3", + "i2c5", + "i2c6", + "nand", + "sd", + "uart0", + "uart1", + "uart2", + "uart3", + "usb0", + "usb1", + "usb2", +}; + +static struct uniphier_pinctrl_socdata ph1_pro5_pinctrl_socdata = { + .pins = ph1_pro5_pins, + .pins_count = ARRAY_SIZE(ph1_pro5_pins), + .groups = ph1_pro5_groups, + .groups_count = ARRAY_SIZE(ph1_pro5_groups), + .functions = ph1_pro5_functions, + .functions_count = ARRAY_SIZE(ph1_pro5_functions), + .mux_bits = 4, + .reg_stride = 8, + .load_pinctrl = true, +}; + +static int ph1_pro5_pinctrl_probe(struct udevice *dev) +{ + return uniphier_pinctrl_probe(dev, &ph1_pro5_pinctrl_socdata); +} + +static const struct udevice_id ph1_pro5_pinctrl_match[] = { + { .compatible = "socionext,ph1-pro5-pinctrl" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(ph1_pro5_pinctrl) = { + .name = "ph1-pro5-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(ph1_pro5_pinctrl_match), + .probe = ph1_pro5_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .priv_auto_alloc_size = sizeof(struct uniphier_pinctrl_priv), + .ops = &uniphier_pinctrl_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c b/drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c new file mode 100644 index 0000000000..5fafdb6100 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <dm/device.h> +#include <dm/pinctrl.h> + +#include "pinctrl-uniphier.h" + +static const struct uniphier_pinctrl_pin ph1_sld8_pins[] = { + UNIPHIER_PINCTRL_PIN(32, 8), + UNIPHIER_PINCTRL_PIN(33, 8), + UNIPHIER_PINCTRL_PIN(34, 8), + UNIPHIER_PINCTRL_PIN(35, 8), + UNIPHIER_PINCTRL_PIN(36, 8), + UNIPHIER_PINCTRL_PIN(37, 8), + UNIPHIER_PINCTRL_PIN(38, 8), + UNIPHIER_PINCTRL_PIN(39, 8), + UNIPHIER_PINCTRL_PIN(40, 9), + UNIPHIER_PINCTRL_PIN(41, 0), + UNIPHIER_PINCTRL_PIN(42, 0), + UNIPHIER_PINCTRL_PIN(43, 0), + UNIPHIER_PINCTRL_PIN(44, 0), + UNIPHIER_PINCTRL_PIN(70, 0), + UNIPHIER_PINCTRL_PIN(71, 0), + UNIPHIER_PINCTRL_PIN(102, 10), + UNIPHIER_PINCTRL_PIN(103, 10), + UNIPHIER_PINCTRL_PIN(104, 11), + UNIPHIER_PINCTRL_PIN(105, 11), + UNIPHIER_PINCTRL_PIN(108, 13), + UNIPHIER_PINCTRL_PIN(109, 13), + UNIPHIER_PINCTRL_PIN(112, 0), + UNIPHIER_PINCTRL_PIN(113, 0), + UNIPHIER_PINCTRL_PIN(114, 0), + UNIPHIER_PINCTRL_PIN(115, 0), +}; + +static const unsigned emmc_pins[] = {21, 22, 23, 24, 25, 26, 27}; +static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1}; +static const unsigned emmc_dat8_pins[] = {28, 29, 30, 31}; +static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1}; +static const unsigned i2c0_pins[] = {102, 103}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {104, 105}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {108, 109}; +static const unsigned i2c2_muxvals[] = {2, 2}; +static const unsigned i2c3_pins[] = {108, 109}; +static const unsigned i2c3_muxvals[] = {3, 3}; +static const unsigned nand_pins[] = {15, 16, 17, 18, 19, 20, 21, 24, 25, 26, + 27, 28, 29, 30, 31}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {22, 23}; +static const unsigned nand_cs1_muxvals[] = {0, 0}; +static const unsigned sd_pins[] = {32, 33, 34, 35, 36, 37, 38, 39, 40}; +static const unsigned sd_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const unsigned uart0_pins[] = {70, 71}; +static const unsigned uart0_muxvals[] = {3, 3}; +static const unsigned uart1_pins[] = {114, 115}; +static const unsigned uart1_muxvals[] = {0, 0}; +static const unsigned uart2_pins[] = {112, 113}; +static const unsigned uart2_muxvals[] = {1, 1}; +static const unsigned uart3_pins[] = {110, 111}; +static const unsigned uart3_muxvals[] = {1, 1}; +static const unsigned usb0_pins[] = {41, 42}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {43, 44}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {114, 115}; +static const unsigned usb2_muxvals[] = {1, 1}; + +static const struct uniphier_pinctrl_group ph1_sld8_groups[] = { + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(sd), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), +}; + +static const char * const ph1_sld8_functions[] = { + "emmc", + "i2c0", + "i2c1", + "i2c2", + "i2c3", + "nand", + "sd", + "uart0", + "uart1", + "uart2", + "uart3", + "usb0", + "usb1", + "usb2", +}; + +static struct uniphier_pinctrl_socdata ph1_sld8_pinctrl_socdata = { + .pins = ph1_sld8_pins, + .pins_count = ARRAY_SIZE(ph1_sld8_pins), + .groups = ph1_sld8_groups, + .groups_count = ARRAY_SIZE(ph1_sld8_groups), + .functions = ph1_sld8_functions, + .functions_count = ARRAY_SIZE(ph1_sld8_functions), + .mux_bits = 8, + .reg_stride = 4, + .load_pinctrl = false, +}; + +static int ph1_sld8_pinctrl_probe(struct udevice *dev) +{ + return uniphier_pinctrl_probe(dev, &ph1_sld8_pinctrl_socdata); +} + +static const struct udevice_id ph1_sld8_pinctrl_match[] = { + { .compatible = "socionext,ph1-sld8-pinctrl" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(ph1_sld8_pinctrl) = { + .name = "ph1-sld8-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(ph1_sld8_pinctrl_match), + .probe = ph1_sld8_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .priv_auto_alloc_size = sizeof(struct uniphier_pinctrl_priv), + .ops = &uniphier_pinctrl_ops, +}; diff --git a/drivers/pinctrl/uniphier/pinctrl-proxstream2.c b/drivers/pinctrl/uniphier/pinctrl-proxstream2.c new file mode 100644 index 0000000000..2cca69d514 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-proxstream2.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <dm/device.h> +#include <dm/pinctrl.h> + +#include "pinctrl-uniphier.h" + +static const struct uniphier_pinctrl_pin proxstream2_pins[] = { + UNIPHIER_PINCTRL_PIN(113, 0), + UNIPHIER_PINCTRL_PIN(114, 0), + UNIPHIER_PINCTRL_PIN(115, 0), + UNIPHIER_PINCTRL_PIN(116, 0), +}; + +static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42}; +static const unsigned emmc_muxvals[] = {9, 9, 9, 9, 9, 9, 9}; +static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46}; +static const unsigned emmc_dat8_muxvals[] = {9, 9, 9, 9}; +static const unsigned i2c0_pins[] = {109, 110}; +static const unsigned i2c0_muxvals[] = {8, 8}; +static const unsigned i2c1_pins[] = {111, 112}; +static const unsigned i2c1_muxvals[] = {8, 8}; +static const unsigned i2c2_pins[] = {171, 172}; +static const unsigned i2c2_muxvals[] = {8, 8}; +static const unsigned i2c3_pins[] = {159, 160}; +static const unsigned i2c3_muxvals[] = {8, 8}; +static const unsigned i2c5_pins[] = {183, 184}; +static const unsigned i2c5_muxvals[] = {11, 11}; +static const unsigned i2c6_pins[] = {185, 186}; +static const unsigned i2c6_muxvals[] = {11, 11}; +static const unsigned nand_pins[] = {30, 31, 32, 33, 34, 35, 36, 39, 40, 41, + 42, 43, 44, 45, 46}; +static const unsigned nand_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8}; +static const unsigned nand_cs1_pins[] = {37, 38}; +static const unsigned nand_cs1_muxvals[] = {8, 8}; +static const unsigned sd_pins[] = {47, 48, 49, 50, 51, 52, 53, 54, 55}; +static const unsigned sd_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8}; +static const unsigned uart0_pins[] = {217, 218}; +static const unsigned uart0_muxvals[] = {8, 8}; +static const unsigned uart0b_pins[] = {179, 180}; +static const unsigned uart0b_muxvals[] = {10, 10}; +static const unsigned uart1_pins[] = {115, 116}; +static const unsigned uart1_muxvals[] = {8, 8}; +static const unsigned uart2_pins[] = {113, 114}; +static const unsigned uart2_muxvals[] = {8, 8}; +static const unsigned uart3_pins[] = {219, 220}; +static const unsigned uart3_muxvals[] = {8, 8}; +static const unsigned uart3b_pins[] = {181, 182}; +static const unsigned uart3b_muxvals[] = {10, 10}; +static const unsigned usb0_pins[] = {56, 57}; +static const unsigned usb0_muxvals[] = {8, 8}; +static const unsigned usb1_pins[] = {58, 59}; +static const unsigned usb1_muxvals[] = {8, 8}; +static const unsigned usb2_pins[] = {60, 61}; +static const unsigned usb2_muxvals[] = {8, 8}; +static const unsigned usb3_pins[] = {62, 63}; +static const unsigned usb3_muxvals[] = {8, 8}; + +static const struct uniphier_pinctrl_group proxstream2_groups[] = { + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(i2c5), + UNIPHIER_PINCTRL_GROUP(i2c6), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(sd), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart0b), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(uart3b), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP(usb3), +}; + +static const char * const proxstream2_functions[] = { + "emmc", + "i2c0", + "i2c1", + "i2c2", + "i2c3", + "i2c5", + "i2c6", + "nand", + "sd", + "uart0", + "uart0b", + "uart1", + "uart2", + "uart3", + "uart3b", + "usb0", + "usb1", + "usb2", + "usb3", +}; + +static struct uniphier_pinctrl_socdata proxstream2_pinctrl_socdata = { + .pins = proxstream2_pins, + .pins_count = ARRAY_SIZE(proxstream2_pins), + .groups = proxstream2_groups, + .groups_count = ARRAY_SIZE(proxstream2_groups), + .functions = proxstream2_functions, + .functions_count = ARRAY_SIZE(proxstream2_functions), + .mux_bits = 8, + .reg_stride = 4, + .load_pinctrl = false, +}; + +static int proxstream2_pinctrl_probe(struct udevice *dev) +{ + return uniphier_pinctrl_probe(dev, &proxstream2_pinctrl_socdata); +} + +static const struct udevice_id proxstream2_pinctrl_match[] = { + { .compatible = "socionext,proxstream2-pinctrl" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(proxstream2_pinctrl) = { + .name = "proxstream2-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(proxstream2_pinctrl_match), + .probe = proxstream2_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .priv_auto_alloc_size = sizeof(struct uniphier_pinctrl_priv), + .ops = &uniphier_pinctrl_ops, +}; diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c new file mode 100644 index 0000000000..37a920ca8b --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <mapmem.h> +#include <linux/io.h> +#include <linux/err.h> +#include <dm/device.h> +#include <dm/pinctrl.h> + +#include "pinctrl-uniphier.h" + +DECLARE_GLOBAL_DATA_PTR; + +static int uniphier_pinctrl_get_groups_count(struct udevice *dev) +{ + struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); + + return priv->socdata->groups_count; +} + +static const char *uniphier_pinctrl_get_group_name(struct udevice *dev, + unsigned selector) +{ + struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); + + return priv->socdata->groups[selector].name; +} + +static int uniphier_pinmux_get_functions_count(struct udevice *dev) +{ + struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); + + return priv->socdata->functions_count; +} + +static const char *uniphier_pinmux_get_function_name(struct udevice *dev, + unsigned selector) +{ + struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); + + return priv->socdata->functions[selector]; +} + +static void uniphier_pinconf_input_enable(struct udevice *dev, unsigned pin) +{ + struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); + int pins_count = priv->socdata->pins_count; + const struct uniphier_pinctrl_pin *pins = priv->socdata->pins; + int i; + + for (i = 0; i < pins_count; i++) { + if (pins[i].number == pin) { + unsigned int iectrl; + u32 tmp; + + iectrl = uniphier_pin_get_iectrl(pins[i].data); + tmp = readl(priv->base + UNIPHIER_PINCTRL_IECTRL); + tmp |= 1 << iectrl; + writel(tmp, priv->base + UNIPHIER_PINCTRL_IECTRL); + } + } +} + +static void uniphier_pinmux_set_one(struct udevice *dev, unsigned pin, + unsigned muxval) +{ + struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); + unsigned mux_bits = priv->socdata->mux_bits; + unsigned reg_stride = priv->socdata->reg_stride; + unsigned reg, reg_end, shift, mask; + u32 tmp; + + reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride; + reg_end = reg + reg_stride; + shift = pin * mux_bits % 32; + mask = (1U << mux_bits) - 1; + + /* + * If reg_stride is greater than 4, the MSB of each pinsel shall be + * stored in the offset+4. + */ + for (; reg < reg_end; reg += 4) { + tmp = readl(priv->base + reg); + tmp &= ~(mask << shift); + tmp |= (mask & muxval) << shift; + writel(tmp, priv->base + reg); + + muxval >>= mux_bits; + } + + if (priv->socdata->load_pinctrl) + writel(1, priv->base + UNIPHIER_PINCTRL_LOAD_PINMUX); + + /* some pins need input-enabling */ + uniphier_pinconf_input_enable(dev, pin); +} + +static int uniphier_pinmux_group_set(struct udevice *dev, + unsigned group_selector, + unsigned func_selector) +{ + struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); + const struct uniphier_pinctrl_group *grp = + &priv->socdata->groups[group_selector]; + int i; + + for (i = 0; i < grp->num_pins; i++) + uniphier_pinmux_set_one(dev, grp->pins[i], grp->muxvals[i]); + + return 0; +} + +const struct pinctrl_ops uniphier_pinctrl_ops = { + .get_groups_count = uniphier_pinctrl_get_groups_count, + .get_group_name = uniphier_pinctrl_get_group_name, + .get_functions_count = uniphier_pinmux_get_functions_count, + .get_function_name = uniphier_pinmux_get_function_name, + .pinmux_group_set = uniphier_pinmux_group_set, + .set_state = pinctrl_generic_set_state, +}; + +int uniphier_pinctrl_probe(struct udevice *dev, + struct uniphier_pinctrl_socdata *socdata) +{ + struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); + fdt_addr_t addr; + fdt_size_t size; + + addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", + &size); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->base = map_sysmem(addr, size); + if (!priv->base) + return -ENOMEM; + + priv->socdata = socdata; + + return 0; +} + +int uniphier_pinctrl_remove(struct udevice *dev) +{ + struct uniphier_pinctrl_priv *priv = dev_get_priv(dev); + + unmap_sysmem(priv->base); + + return 0; +} diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier.h b/drivers/pinctrl/uniphier/pinctrl-uniphier.h new file mode 100644 index 0000000000..7eaec6a702 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __PINCTRL_UNIPHIER_H__ +#define __PINCTRL_UNIPHIER_H__ + +/* TODO: move this to include/linux/bug.h */ +#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) + +#include <linux/kernel.h> +#include <linux/types.h> + +#define UNIPHIER_PINCTRL_PINMUX_BASE 0x0 +#define UNIPHIER_PINCTRL_LOAD_PINMUX 0x700 +#define UNIPHIER_PINCTRL_IECTRL 0xd00 + +#define UNIPHIER_PIN_ATTR_PACKED(iectrl) (iectrl) + +static inline unsigned int uniphier_pin_get_iectrl(unsigned long data) +{ + return data; +} + +/** + * struct uniphier_pinctrl_pin - pin data for UniPhier SoC + * + * @number: pin number + * @data: additional per-pin data + */ +struct uniphier_pinctrl_pin { + unsigned number; + unsigned long data; +}; + +/** + * struct uniphier_pinctrl_group - pin group data for UniPhier SoC + * + * @name: pin group name + * @pins: array of pins that belong to the group + * @num_pins: number of pins in the group + * @muxvals: array of values to be set to pinmux registers + */ +struct uniphier_pinctrl_group { + const char *name; + const unsigned *pins; + unsigned num_pins; + const unsigned *muxvals; +}; + +/** + * struct uniphier_pinctrl_socdata - SoC data for UniPhier pin controller + * + * @pins: array of pin data + * @pins_count: number of pin data + * @groups: array of pin group data + * @groups_count: number of pin group data + * @functions: array of pinmux function names + * @functions_count: number of pinmux functions + * @mux_bits: bit width of each pinmux register + * @reg_stride: stride of pinmux register address + * @load_pinctrl: if true, LOAD_PINMUX register must be set to one for new + * values in pinmux registers to become really effective + */ +struct uniphier_pinctrl_socdata { + const struct uniphier_pinctrl_pin *pins; + int pins_count; + const struct uniphier_pinctrl_group *groups; + int groups_count; + const char * const *functions; + int functions_count; + unsigned mux_bits; + unsigned reg_stride; + bool load_pinctrl; +}; + +#define UNIPHIER_PINCTRL_PIN(a, b) \ +{ \ + .number = a, \ + .data = UNIPHIER_PIN_ATTR_PACKED(b), \ +} + +#define UNIPHIER_PINCTRL_GROUP(grp) \ + { \ + .name = #grp, \ + .pins = grp##_pins, \ + .num_pins = ARRAY_SIZE(grp##_pins), \ + .muxvals = grp##_muxvals + \ + BUILD_BUG_ON_ZERO(ARRAY_SIZE(grp##_pins) != \ + ARRAY_SIZE(grp##_muxvals)), \ + } + +/** + * struct uniphier_pinctrl_priv - private data for UniPhier pinctrl driver + * + * @base: base address of the pinctrl device + * @socdata: SoC specific data + */ +struct uniphier_pinctrl_priv { + void __iomem *base; + struct uniphier_pinctrl_socdata *socdata; +}; + +extern const struct pinctrl_ops uniphier_pinctrl_ops; + +int uniphier_pinctrl_probe(struct udevice *dev, + struct uniphier_pinctrl_socdata *socdata); + +int uniphier_pinctrl_remove(struct udevice *dev); + +#endif /* __PINCTRL_UNIPHIER_H__ */ diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index ccb80d2d1d..ddb725d326 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -111,7 +111,7 @@ config DEBUG_UART_SHIFT config ROCKCHIP_SERIAL bool "Rockchip on-chip UART support" - depends on ARCH_UNIPHIER && DM_SERIAL + depends on ARCH_ROCKCHIP && DM_SERIAL help Select this to enable a debug UART for Rockchip devices. This uses the ns16550 driver. You will need to #define CONFIG_SYS_NS16550 in diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index ecf3bc0240..3a5c1d0eaa 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -80,13 +80,6 @@ static int pl01x_generic_serial_init(struct pl01x_regs *regs, writel(0, ®s->pl010_cr); break; case TYPE_PL011: -#ifdef CONFIG_PL011_SERIAL_FLUSH_ON_INIT - /* Empty RX fifo if necessary */ - if (readl(®s->pl011_cr) & UART_PL011_CR_UARTEN) { - while (!(readl(®s->fr) & UART_PL01x_FR_RXFE)) - readl(®s->dr); - } -#endif /* disable everything */ writel(0, ®s->pl011_cr); break; @@ -105,21 +98,6 @@ static int pl011_set_line_control(struct pl01x_regs *regs) * control register write */ lcr = UART_PL011_LCRH_WLEN_8 | UART_PL011_LCRH_FEN; -#ifdef CONFIG_PL011_SERIAL_RLCR - { - int i; - - /* - * Program receive line control register after waiting - * 10 bus cycles. Delay be writing to readonly register - * 10 times - */ - for (i = 0; i < 10; i++) - writel(lcr, ®s->fr); - - writel(lcr, ®s->pl011_rlcr); - } -#endif writel(lcr, ®s->pl011_lcrh); return 0; } diff --git a/drivers/serial/serial_sh.h b/drivers/serial/serial_sh.h index 941e6eda4c..cbc2929435 100644 --- a/drivers/serial/serial_sh.h +++ b/drivers/serial/serial_sh.h @@ -226,7 +226,11 @@ struct uart_port { # define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ #elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \ defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794) -# define SCIF_ORER 0x0001 +# if defined(CONFIG_SCIF_A) +# define SCIF_ORER 0x0200 +# else +# define SCIF_ORER 0x0001 +# endif # define SCSCR_INIT(port) (port->clk_mode == EXT_CLK ? 0x32 : 0x30) /* TIE=0,RIE=0,TE=1,RE=1,REIE=0, */ #else @@ -306,7 +310,11 @@ struct uart_port { #elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \ defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794) # define SCIF_ERRORS (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK) -# define SCIF_RFDC_MASK 0x003f +# if defined(CONFIG_SCIF_A) +# define SCIF_RFDC_MASK 0x007f +# else +# define SCIF_RFDC_MASK 0x001f +# endif #else # define SCIF_ERRORS (SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK) # define SCIF_RFDC_MASK 0x001f @@ -557,6 +565,25 @@ SCIF_FNS(SCFCR, 0x18, 16) SCIF_FNS(SCFDR, 0x1c, 16) SCIF_FNS(SCLSR, 0x24, 16) SCIF_FNS(DL, 0x00, 0) /* dummy */ +#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \ + defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794) +/* SCIFA and SCIF register offsets and size */ +SCIx_FNS(SCSMR, 0, 0, 0x00, 16, 0, 0, 0x00, 16, 0, 0) +SCIx_FNS(SCBRR, 0, 0, 0x04, 8, 0, 0, 0x04, 8, 0, 0) +SCIx_FNS(SCSCR, 0, 0, 0x08, 16, 0, 0, 0x08, 16, 0, 0) +SCIx_FNS(SCxTDR, 0, 0, 0x20, 8, 0, 0, 0x0C, 8, 0, 0) +SCIx_FNS(SCxSR, 0, 0, 0x14, 16, 0, 0, 0x10, 16, 0, 0) +SCIx_FNS(SCxRDR, 0, 0, 0x24, 8, 0, 0, 0x14, 8, 0, 0) +SCIF_FNS(SCFCR, 0, 0, 0x18, 16) +SCIF_FNS(SCFDR, 0, 0, 0x1C, 16) +SCIF_FNS(SCSPTR, 0, 0, 0x20, 16) +SCIF_FNS(DL, 0, 0, 0x30, 16) +SCIF_FNS(CKS, 0, 0, 0x34, 16) +#if defined(CONFIG_SCIF_A) +SCIF_FNS(SCLSR, 0, 0, 0x14, 16) +#else +SCIF_FNS(SCLSR, 0, 0, 0x24, 16) +#endif #else /* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 SCI/H8*/ /* name off sz off sz off sz off sz off sz*/ @@ -594,14 +621,8 @@ SCIF_FNS(SCSPTR, 0, 0, 0x20, 16) #endif SCIF_FNS(SCLSR, 0, 0, 0x24, 16) #endif -#if defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \ - defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794) -SCIF_FNS(DL, 0, 0, 0x30, 16) -SCIF_FNS(CKS, 0, 0, 0x34, 16) -#else SCIF_FNS(DL, 0, 0, 0x0, 0) /* dummy */ #endif -#endif #define sci_in(port, reg) sci_##reg##_in(port) #define sci_out(port, reg, value) sci_##reg##_out(port, value) @@ -743,7 +764,11 @@ static inline int scbrr_calc(struct uart_port *port, int bps, int clk) #elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \ defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794) #define DL_VALUE(bps, clk) (clk / bps / 16) /* External Clock */ -#define SCBRR_VALUE(bps, clk) (clk / bps / 32 - 1) /* Internal Clock */ + #if defined(CONFIG_SCIF_A) + #define SCBRR_VALUE(bps, clk) (clk / bps / 16 - 1) /* Internal Clock */ + #else + #define SCBRR_VALUE(bps, clk) (clk / bps / 32 - 1) /* Internal Clock */ + #endif #else /* Generic SH */ #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1) #endif diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 0a036ccb00..0bd4f88926 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -15,8 +15,6 @@ #include <asm/io.h> #include <asm/arch/hardware.h> -#define BIT(x) (1 << (x)) - /* SPIGCR0 */ #define SPIGCR0_SPIENA_MASK 0x1 #define SPIGCR0_SPIRST_MASK 0x0 diff --git a/drivers/spi/ep93xx_spi.c b/drivers/spi/ep93xx_spi.c index 235557ea3c..cb682ddda4 100644 --- a/drivers/spi/ep93xx_spi.c +++ b/drivers/spi/ep93xx_spi.c @@ -16,8 +16,6 @@ #include <asm/arch/ep93xx.h> - -#define BIT(x) (1<<(x)) #define SSPBASE SPI_BASE #define SSPCR0 0x0000 diff --git a/drivers/spi/mxs_spi.c b/drivers/spi/mxs_spi.c index 2b9f395a97..627644b56b 100644 --- a/drivers/spi/mxs_spi.c +++ b/drivers/spi/mxs_spi.c @@ -12,6 +12,7 @@ #include <common.h> #include <malloc.h> +#include <memalign.h> #include <spi.h> #include <asm/errno.h> #include <asm/io.h> diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c index fbb665b86f..144716fd91 100644 --- a/drivers/spi/tegra20_slink.c +++ b/drivers/spi/tegra20_slink.c @@ -36,6 +36,11 @@ DECLARE_GLOBAL_DATA_PTR; #define SLINK_CMD_ENB (1 << 31) #define SLINK_CMD_GO (1 << 30) #define SLINK_CMD_M_S (1 << 28) +#define SLINK_CMD_IDLE_SCLK_DRIVE_LOW (0 << 24) +#define SLINK_CMD_IDLE_SCLK_DRIVE_HIGH (1 << 24) +#define SLINK_CMD_IDLE_SCLK_PULL_LOW (2 << 24) +#define SLINK_CMD_IDLE_SCLK_PULL_HIGH (3 << 24) +#define SLINK_CMD_IDLE_SCLK_MASK (3 << 24) #define SLINK_CMD_CK_SDA (1 << 21) #define SLINK_CMD_CS_POL (1 << 13) #define SLINK_CMD_CS_VAL (1 << 12) @@ -331,6 +336,22 @@ static int tegra30_spi_set_speed(struct udevice *bus, uint speed) static int tegra30_spi_set_mode(struct udevice *bus, uint mode) { struct tegra30_spi_priv *priv = dev_get_priv(bus); + struct spi_regs *regs = priv->regs; + u32 reg; + + reg = readl(®s->command); + + /* Set CPOL and CPHA */ + reg &= ~(SLINK_CMD_IDLE_SCLK_MASK | SLINK_CMD_CK_SDA); + if (mode & SPI_CPHA) + reg |= SLINK_CMD_CK_SDA; + + if (mode & SPI_CPOL) + reg |= SLINK_CMD_IDLE_SCLK_DRIVE_HIGH; + else + reg |= SLINK_CMD_IDLE_SCLK_DRIVE_LOW; + + writel(reg, ®s->command); priv->mode = mode; debug("%s: regs=%p, mode=%d\n", __func__, priv->regs, priv->mode); diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 6c21acda57..8ccc5780c9 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -247,7 +247,7 @@ static int xilinx_spi_set_speed(struct udevice *bus, uint speed) priv->freq = speed; - debug("xilinx_spi_set_speed: regs=%p, mode=%d\n", priv->regs, + debug("xilinx_spi_set_speed: regs=%p, speed=%d\n", priv->regs, priv->freq); return 0; @@ -260,13 +260,13 @@ static int xilinx_spi_set_mode(struct udevice *bus, uint mode) uint32_t spicr; spicr = readl(®s->spicr); - if (priv->mode & SPI_LSB_FIRST) + if (mode & SPI_LSB_FIRST) spicr |= SPICR_LSB_FIRST; - if (priv->mode & SPI_CPHA) + if (mode & SPI_CPHA) spicr |= SPICR_CPHA; - if (priv->mode & SPI_CPOL) + if (mode & SPI_CPOL) spicr |= SPICR_CPOL; - if (priv->mode & SPI_LOOP) + if (mode & SPI_LOOP) spicr |= SPICR_LOOP; writel(spicr, ®s->spicr); diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c index 310fb69c8d..d370e495cd 100644 --- a/drivers/spi/zynq_spi.c +++ b/drivers/spi/zynq_spi.c @@ -272,7 +272,8 @@ static int zynq_spi_set_speed(struct udevice *bus, uint speed) writel(confr, ®s->cr); priv->freq = speed; - debug("zynq_spi_set_speed: regs=%p, mode=%d\n", priv->regs, priv->freq); + debug("zynq_spi_set_speed: regs=%p, speed=%d\n", + priv->regs, priv->freq); return 0; } @@ -287,9 +288,9 @@ static int zynq_spi_set_mode(struct udevice *bus, uint mode) confr = readl(®s->cr); confr &= ~(ZYNQ_SPI_CR_CPHA_MASK | ZYNQ_SPI_CR_CPOL_MASK); - if (priv->mode & SPI_CPHA) + if (mode & SPI_CPHA) confr |= ZYNQ_SPI_CR_CPHA_MASK; - if (priv->mode & SPI_CPOL) + if (mode & SPI_CPOL) confr |= ZYNQ_SPI_CR_CPOL_MASK; writel(confr, ®s->cr); diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 6d4cacdcf7..d768f5ef80 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -6,4 +6,4 @@ # obj-$(CONFIG_DM_THERMAL) += thermal-uclass.o -obj-$(CONFIG_IMX6_THERMAL) += imx_thermal.o +obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 3c6c9679f9..09a3c52680 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -25,6 +25,9 @@ #define FACTOR1 15976 #define FACTOR2 4297157 #define MEASURE_FREQ 327 +#define TEMPERATURE_MIN -40 +#define TEMPERATURE_HOT 85 +#define TEMPERATURE_MAX 125 #define TEMPSENSE0_TEMP_CNT_SHIFT 8 #define TEMPSENSE0_TEMP_CNT_MASK (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT) @@ -41,6 +44,7 @@ struct thermal_data { int maxc; }; +#if defined(CONFIG_MX6) static int read_cpu_temperature(struct udevice *dev) { int temperature; @@ -123,6 +127,73 @@ static int read_cpu_temperature(struct udevice *dev) return temperature; } +#elif defined(CONFIG_MX7) +static int read_cpu_temperature(struct udevice *dev) +{ + unsigned int reg, tmp, start; + unsigned int raw_25c, te1; + int temperature; + unsigned int *priv = dev_get_priv(dev); + u32 fuse = *priv; + struct mxc_ccm_anatop_reg *ccm_anatop = (struct mxc_ccm_anatop_reg *) + ANATOP_BASE_ADDR; + /* + * fuse data layout: + * [31:21] sensor value @ 25C + * [20:18] hot temperature value + * [17:9] sensor value of room + * [8:0] sensor value of hot + */ + + raw_25c = fuse >> 21; + if (raw_25c == 0) + raw_25c = 25; + + te1 = (fuse >> 9) & 0x1ff; + + /* + * now we only use single measure, every time we read + * the temperature, we will power on/down anadig thermal + * module + */ + writel(TEMPMON_HW_ANADIG_TEMPSENSE1_POWER_DOWN_MASK, &ccm_anatop->tempsense1_clr); + writel(PMU_REF_REFTOP_SELFBIASOFF_MASK, &ccm_anatop->ref_set); + + /* write measure freq */ + reg = readl(&ccm_anatop->tempsense1); + reg &= ~TEMPMON_HW_ANADIG_TEMPSENSE1_MEASURE_FREQ_MASK; + reg |= TEMPMON_HW_ANADIG_TEMPSENSE1_MEASURE_FREQ(MEASURE_FREQ); + writel(reg, &ccm_anatop->tempsense1); + + writel(TEMPMON_HW_ANADIG_TEMPSENSE1_MEASURE_TEMP_MASK, &ccm_anatop->tempsense1_clr); + writel(TEMPMON_HW_ANADIG_TEMPSENSE1_FINISHED_MASK, &ccm_anatop->tempsense1_clr); + writel(TEMPMON_HW_ANADIG_TEMPSENSE1_MEASURE_TEMP_MASK, &ccm_anatop->tempsense1_set); + + start = get_timer(0); + /* Wait max 100ms */ + do { + /* + * Since we can not rely on finish bit, use 1ms delay to get + * temperature. From RM, 17us is enough to get data, but + * to gurantee to get the data, delay 100ms here. + */ + reg = readl(&ccm_anatop->tempsense1); + tmp = (reg & TEMPMON_HW_ANADIG_TEMPSENSE1_TEMP_VALUE_MASK) + >> TEMPMON_HW_ANADIG_TEMPSENSE1_TEMP_VALUE_SHIFT; + } while (get_timer(0) < (start + 100)); + + writel(TEMPMON_HW_ANADIG_TEMPSENSE1_FINISHED_MASK, &ccm_anatop->tempsense1_clr); + + /* power down anatop thermal sensor */ + writel(TEMPMON_HW_ANADIG_TEMPSENSE1_POWER_DOWN_MASK, &ccm_anatop->tempsense1_set); + writel(PMU_REF_REFTOP_SELFBIASOFF_MASK, &ccm_anatop->ref_clr); + + /* Single point */ + temperature = tmp - (te1 - raw_25c); + + return temperature; +} +#endif int imx_thermal_get_temp(struct udevice *dev, int *temp) { @@ -130,6 +201,7 @@ int imx_thermal_get_temp(struct udevice *dev, int *temp) int cpu_tmp = 0; cpu_tmp = read_cpu_temperature(dev); + while (cpu_tmp >= priv->critical) { printf("CPU Temperature (%dC) too close to max (%dC)", cpu_tmp, priv->maxc); @@ -157,10 +229,20 @@ static int imx_thermal_probe(struct udevice *dev) /* Read Temperature calibration data fuse */ fuse_read(pdata->fuse_bank, pdata->fuse_word, &fuse); - /* Check for valid fuse */ - if (fuse == 0 || fuse == ~0) { - printf("CPU: Thermal invalid data, fuse: 0x%x\n", fuse); - return -EPERM; + if (is_soc_type(MXC_SOC_MX6)) { + /* Check for valid fuse */ + if (fuse == 0 || fuse == ~0) { + debug("CPU: Thermal invalid data, fuse: 0x%x\n", + fuse); + return -EPERM; + } + } else if (is_soc_type(MXC_SOC_MX7)) { + /* No Calibration data in FUSE? */ + if ((fuse & 0x3ffff) == 0) + return -EPERM; + /* We do not support 105C TE2 */ + if (((fuse & 0x1c0000) >> 18) == 0x6) + return -EPERM; } /* set critical cooling temp */ diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c index 8a43e7c27d..ad083cf8ae 100644 --- a/drivers/usb/eth/asix.c +++ b/drivers/usb/eth/asix.c @@ -10,6 +10,7 @@ #include <dm.h> #include <usb.h> #include <malloc.h> +#include <memalign.h> #include <linux/mii.h> #include "usb_ether.h" diff --git a/drivers/usb/eth/asix88179.c b/drivers/usb/eth/asix88179.c index 94dfe85eff..cf4085d765 100644 --- a/drivers/usb/eth/asix88179.c +++ b/drivers/usb/eth/asix88179.c @@ -12,6 +12,7 @@ #include <linux/mii.h> #include "usb_ether.h" #include <malloc.h> +#include <memalign.h> #include <errno.h> /* ASIX AX88179 based USB 3.0 Ethernet Devices */ diff --git a/drivers/usb/eth/mcs7830.c b/drivers/usb/eth/mcs7830.c index c1b708600e..bbdad8b79a 100644 --- a/drivers/usb/eth/mcs7830.c +++ b/drivers/usb/eth/mcs7830.c @@ -14,6 +14,7 @@ #include <errno.h> #include <linux/mii.h> #include <malloc.h> +#include <memalign.h> #include <usb.h> #include "usb_ether.h" diff --git a/drivers/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c index 1dcd088b8d..dc8fa8891b 100644 --- a/drivers/usb/eth/smsc95xx.c +++ b/drivers/usb/eth/smsc95xx.c @@ -11,6 +11,7 @@ #include <dm.h> #include <errno.h> #include <malloc.h> +#include <memalign.h> #include <usb.h> #include <asm/unaligned.h> #include <linux/mii.h> diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c index 3e8eb8799f..1ba5054965 100644 --- a/drivers/usb/gadget/ci_udc.c +++ b/drivers/usb/gadget/ci_udc.c @@ -87,6 +87,7 @@ static int ci_ep_enable(struct usb_ep *ep, static int ci_ep_disable(struct usb_ep *ep); static int ci_ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags); +static int ci_ep_dequeue(struct usb_ep *ep, struct usb_request *req); static struct usb_request * ci_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags); static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *_req); @@ -99,6 +100,7 @@ static struct usb_ep_ops ci_ep_ops = { .enable = ci_ep_enable, .disable = ci_ep_disable, .queue = ci_ep_queue, + .dequeue = ci_ep_dequeue, .alloc_request = ci_ep_alloc_request, .free_request = ci_ep_free_request, }; @@ -424,7 +426,7 @@ static void ci_ep_submit_next_request(struct ci_ep *ci_ep) int bit, num, len, in; struct ci_req *ci_req; u8 *buf; - uint32_t length, actlen; + uint32_t len_left, len_this_dtd; struct ept_queue_item *dtd, *qtd; ci_ep->req_primed = true; @@ -442,25 +444,23 @@ static void ci_ep_submit_next_request(struct ci_ep *ci_ep) ci_req->dtd_count = 0; buf = ci_req->hw_buf; - actlen = 0; + len_left = len; dtd = item; do { - length = min(ci_req->req.length - actlen, - (unsigned)EP_MAX_LENGTH_TRANSFER); + len_this_dtd = min(len_left, (unsigned)EP_MAX_LENGTH_TRANSFER); - dtd->info = INFO_BYTES(length) | INFO_ACTIVE; + dtd->info = INFO_BYTES(len_this_dtd) | INFO_ACTIVE; dtd->page0 = (unsigned long)buf; dtd->page1 = ((unsigned long)buf & 0xfffff000) + 0x1000; dtd->page2 = ((unsigned long)buf & 0xfffff000) + 0x2000; dtd->page3 = ((unsigned long)buf & 0xfffff000) + 0x3000; dtd->page4 = ((unsigned long)buf & 0xfffff000) + 0x4000; - len -= length; - actlen += length; - buf += length; + len_left -= len_this_dtd; + buf += len_this_dtd; - if (len) { + if (len_left) { qtd = (struct ept_queue_item *) memalign(ILIST_ALIGN, ILIST_ENT_SZ); dtd->next = (unsigned long)qtd; @@ -469,7 +469,7 @@ static void ci_ep_submit_next_request(struct ci_ep *ci_ep) } ci_req->dtd_count++; - } while (len); + } while (len_left); item = dtd; /* @@ -525,6 +525,30 @@ static void ci_ep_submit_next_request(struct ci_ep *ci_ep) writel(bit, &udc->epprime); } +static int ci_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct ci_ep *ci_ep = container_of(_ep, struct ci_ep, ep); + struct ci_req *ci_req; + + list_for_each_entry(ci_req, &ci_ep->queue, queue) { + if (&ci_req->req == _req) + break; + } + + if (&ci_req->req != _req) + return -EINVAL; + + list_del_init(&ci_req->queue); + + if (ci_req->req.status == -EINPROGRESS) { + ci_req->req.status = -ECONNRESET; + if (ci_req->req.complete) + ci_req->req.complete(_ep, _req); + } + + return 0; +} + static int ci_ep_queue(struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags) { diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index d96296cd73..a13b21d0a0 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -948,6 +948,7 @@ static void composite_unbind(struct usb_gadget *gadget) debug("unbind config '%s'/%p\n", c->label, c); c->unbind(c); } + free(c); } if (composite->unbind) composite->unbind(cdev); diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 53f4672291..c5e35ee350 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -17,6 +17,7 @@ #include <net.h> #include <usb.h> #include <malloc.h> +#include <memalign.h> #include <linux/ctype.h> #include "gadget_chips.h" diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c index 06139ee04d..ff1481ba37 100644 --- a/drivers/usb/gadget/f_thor.c +++ b/drivers/usb/gadget/f_thor.c @@ -18,6 +18,7 @@ #include <errno.h> #include <common.h> #include <malloc.h> +#include <memalign.h> #include <version.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c index ad89a0d2e6..2fa6da4091 100644 --- a/drivers/usb/gadget/g_dnl.c +++ b/drivers/usb/gadget/g_dnl.c @@ -93,8 +93,6 @@ static int g_dnl_unbind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; - free(cdev->config); - cdev->config = NULL; debug("%s: calling usb_gadget_disconnect for " "controller '%s'\n", __func__, gadget->name); usb_gadget_disconnect(gadget); diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index 85236aeb2a..541c0f9687 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -10,6 +10,7 @@ #include <errno.h> #include <usb.h> #include <malloc.h> +#include <memalign.h> #include <phys2bus.h> #include <usbroothubdes.h> #include <asm/io.h> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 88b670b7f8..135ef72622 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -15,6 +15,7 @@ #include <usb.h> #include <asm/io.h> #include <malloc.h> +#include <memalign.h> #include <watchdog.h> #include <linux/compiler.h> diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 0ffd838db2..9bde2b252c 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -41,6 +41,7 @@ #endif #include <malloc.h> +#include <memalign.h> #include <usb.h> #include "ohci.h" diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index b17a7d762e..c66ebb6678 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -10,6 +10,7 @@ #include <common.h> #include <dm.h> #include <errno.h> +#include <memalign.h> #include <usb.h> #include <dm/device-internal.h> #include <dm/lists.h> diff --git a/drivers/usb/musb-new/musb_core.c b/drivers/usb/musb-new/musb_core.c index 411e5a0884..d1b6d15c8e 100644 --- a/drivers/usb/musb-new/musb_core.c +++ b/drivers/usb/musb-new/musb_core.c @@ -1550,7 +1550,7 @@ static int __devinit musb_core_init(u16 musb_type, struct musb *musb) /*-------------------------------------------------------------------------*/ #if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \ - defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500) + defined(CONFIG_ARCH_OMAP4) static irqreturn_t generic_interrupt(int irq, void *__hci) { diff --git a/drivers/video/anx9804.c b/drivers/video/anx9804.c index 83d60d672d..37ad69a039 100755 --- a/drivers/video/anx9804.c +++ b/drivers/video/anx9804.c @@ -14,8 +14,6 @@ #include <i2c.h> #include "anx9804.h" -#define BIT(x) (1 << (x)) - /* Registers at i2c address 0x38 */ #define ANX9804_HDCP_CONTROL_0_REG 0x01 diff --git a/drivers/video/bcm2835.c b/drivers/video/bcm2835.c index 61d054dd89..7867fe3895 100644 --- a/drivers/video/bcm2835.c +++ b/drivers/video/bcm2835.c @@ -6,6 +6,7 @@ #include <common.h> #include <lcd.h> +#include <memalign.h> #include <asm/arch/mbox.h> #include <asm/global_data.h> diff --git a/drivers/video/mb862xx.c b/drivers/video/mb862xx.c index 868c51254d..1c74e97c5e 100644 --- a/drivers/video/mb862xx.c +++ b/drivers/video/mb862xx.c @@ -419,7 +419,8 @@ void *video_hw_init (void) board_disp_init (); #endif -#if defined(CONFIG_SOCRATES) && !(CONFIG_POST & CONFIG_SYS_POST_SYSMON) +#if (defined(CONFIG_LWMON5) || \ + defined(CONFIG_SOCRATES)) && !(CONFIG_POST & CONFIG_SYS_POST_SYSMON) /* Lamp on */ board_backlight_switch (1); #endif diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 482a4bd5be..a007ae8234 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_AT91SAM9_WATCHDOG) += at91sam9_wdt.o obj-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o -ifneq (,$(filter $(SOC), mx31 mx35 mx5 mx6 vf610 ls102xa)) +ifneq (,$(filter $(SOC), mx31 mx35 mx5 mx6 mx7 vf610)) obj-y += imx_watchdog.o endif obj-$(CONFIG_S5P) += s5p_wdt.o diff --git a/drivers/watchdog/imx_watchdog.c b/drivers/watchdog/imx_watchdog.c index 1d18d4b269..0d775956bf 100644 --- a/drivers/watchdog/imx_watchdog.c +++ b/drivers/watchdog/imx_watchdog.c @@ -8,19 +8,7 @@ #include <asm/io.h> #include <watchdog.h> #include <asm/arch/imx-regs.h> - -struct watchdog_regs { - u16 wcr; /* Control */ - u16 wsr; /* Service */ - u16 wrsr; /* Reset Status */ -}; - -#define WCR_WDZST 0x01 -#define WCR_WDBG 0x02 -#define WCR_WDE 0x04 /* WDOG enable */ -#define WCR_WDT 0x08 -#define WCR_SRS 0x10 -#define SET_WCR_WT(x) (x << 8) +#include <fsl_wdog.h> #ifdef CONFIG_IMX_WATCHDOG void hw_watchdog_reset(void) @@ -55,7 +43,8 @@ void reset_cpu(ulong addr) { struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR; - writew(WCR_WDE, &wdog->wcr); + clrsetbits_le16(&wdog->wcr, 0, WCR_WDE); + writew(0x5555, &wdog->wsr); writew(0xaaaa, &wdog->wsr); /* load minimum 1/2 second timeout */ while (1) { |