diff options
author | Wolfgang Denk <wd@denx.de> | 2011-10-27 22:15:19 (GMT) |
---|---|---|
committer | Wolfgang Denk <wd@denx.de> | 2011-10-27 22:15:19 (GMT) |
commit | 87a5d601031652293ec4b729fdb7ee01bbd940a8 (patch) | |
tree | 91ede3ee45b228736c1876a700024782d7bc2032 /drivers | |
parent | 606a76f8ef479e42ae4d06f8f3ce87e9a1c72acf (diff) | |
parent | 37fc0ed268dc5acacd3a83adafa26eb1a84e90af (diff) | |
download | u-boot-fsl-qoriq-87a5d601031652293ec4b729fdb7ee01bbd940a8.tar.xz |
Merge branch 'master' of git://git.denx.de/u-boot-arm
* 'master' of git://git.denx.de/u-boot-arm:
ARM: Add Calxeda Highbank platform
dkb: make mmc command as default enabled
Marvell: dkb: add mmc support
ARM: pantheon: add mmc definition
davinci: remove config.mk file from the sources
ARM:AM33XX: Add support for TI AM335X EVM
ARM:AM33XX: Added timer support
ARM:AM33XX: Add emif/ddr support
ARM:AM33XX: Add clock definitions
ARM:AM33XX: Added support for AM33xx
omap3/emif4: fix registers definition
davinci: remove obsolete macro CONFIG_EMAC_MDIO_PHY_NUM
davinci: emac: add support for more than 1 PHYs
davinci: emac: add new features to autonegotiate for EMAC
da850evm: Move LPSC configuration to board_early_init_f()
omap4_panda: Build in cmd_gpio support on panda
omap: Don't use gpio_free to change direction to input
mmc: omap: Allow OMAP_HSMMC[23]_BASE to be unset
OMAP3: overo : Add environment variable optargs to bootargs
OMAP3: overo: Move ethernet CS4 configuration to execute based on board id
OMAP3: overo : Use ttyO2 instead of ttyS2.
da830: add support for NAND boot mode
dm36x: revert cache disable patch
dm644X: revert cache disable patch
devkit8000: Add malloc space
omap: spl: fix build break due to changes in FAT
OMAP3 SPL: Provide weak omap_rev_string
omap: beagle: Use ubifs instead of jffs2 for nand boot
omap: overo: Disable pull-ups on camera PCLK, HS and VS signals
omap: overo: Configure mux for gpio10
SPL: Add DMA library
omap3: Add interface for omap3 DMA
omap3: Add DMA register accessors
omap3: Add Base register for DMA
arm, davinci: add missing LSPC define for MMC/SD1
U-Boot/SPL: omap4: Make ddr pre-calculated timings as default.
DaVinci: correct MDSTAT.STATE mask
omap4: splitting padconfs into common, 4430 and 4460
omap4: adding revision detection for 4460 ES1.1
omap4: replacing OMAP4_CONTROL with OMAP4430_CONTROL
gplug: fixed build error as a result of code cleanup patch
kirkwood_spi: add dummy spi_init()
gpio: mvmfp: reduce include platform file
ARM: orion5x: reduce dependence of including platform file
serial: reduce include platform file for marvell chip
ARM: kirkwood: reduce dependence of including platform file
ARM: armada100: reduce dependence of including platform file
ARM: pantheon: reduce dependence of including platform file
Armada100: Add env storage support for Marvell gplugD
Armada100: Add SPI flash support for Marvell gplugD
Armada100: Add SPI support for Marvell gplugD
SPI: Add SPI driver support for Marvell Armada100
dreamplug: initial board support.
imx: fix coding style
misc: pmic: drop old Freescale's pmic driver
MX31: mx31pdk: use new pmic driver
MX31: mx31ads: use new pmic driver
MX31: mx31_litekit: use new pmic driver
MX5: mx53evk: use new pmic driver
MX5: mx51evk: use new pmic driver
MX35: mx35pdk: use new pmic driver
misc: pmic: addI2C support to pmic_fsl driver
misc: pmic: use I2C_SET_BUS in pmic I2C
MX5: efikamx/efikasb: use new pmic driver
MX3: qong: use new pmic driver
RTC: Switch mc13783 to generic pmic code
MX5: vision2: use new pmic driver
misc: pmic: Freescale PMIC switches to generic PMIC driver
misc:pmic:samsung Enable PMIC driver at GONI target
misc:pmic:max8998 MAX8998 support at a new PMIC driver.
misc:pmic:core New generic PMIC driver
mx31pdk: Remove unneeded config
mx31: provide readable WEIM CS accessor
MX51: vision2: Set global macros
I2C: Add i2c_get/set_speed() to mxc_i2c.c
ARM: Update mach-types
devkit8000: Add config to enable SPL MMC boot
devkit8000: protect board_mmc_init
arm, post: add missing post_time_ms for arm
cosmetic, post: Codingstyle cleanup
arm, logbuffer: make it compileclean
tegra2: Enable MMC for Seaboard
tegra2: Add more pinmux functions
tegra2: Rename PIN_ to PINGRP_
tegra2: Add more clock functions
tegra2: Clean up board code a little
tegra2: Rename CLOCK_PLL_ID to CLOCK_ID
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/dma/Makefile | 1 | ||||
-rw-r--r-- | drivers/dma/omap3_dma.c | 180 | ||||
-rw-r--r-- | drivers/gpio/kw_gpio.c | 1 | ||||
-rw-r--r-- | drivers/gpio/mvmfp.c | 7 | ||||
-rw-r--r-- | drivers/i2c/mxc_i2c.c | 31 | ||||
-rw-r--r-- | drivers/misc/Makefile | 6 | ||||
-rw-r--r-- | drivers/misc/fsl_pmic.c | 235 | ||||
-rw-r--r-- | drivers/misc/pmic_core.c | 147 | ||||
-rw-r--r-- | drivers/misc/pmic_fsl.c | 66 | ||||
-rw-r--r-- | drivers/misc/pmic_i2c.c | 92 | ||||
-rw-r--r-- | drivers/misc/pmic_max8998.c | 43 | ||||
-rw-r--r-- | drivers/misc/pmic_spi.c | 109 | ||||
-rw-r--r-- | drivers/mmc/omap_hsmmc.c | 4 | ||||
-rw-r--r-- | drivers/mmc/tegra2_mmc.c | 94 | ||||
-rw-r--r-- | drivers/mmc/tegra2_mmc.h | 1 | ||||
-rw-r--r-- | drivers/net/davinci_emac.c | 209 | ||||
-rw-r--r-- | drivers/net/mvgbe.c | 2 | ||||
-rw-r--r-- | drivers/rtc/mc13783-rtc.c | 20 | ||||
-rw-r--r-- | drivers/serial/ns16550.c | 7 | ||||
-rw-r--r-- | drivers/serial/serial.c | 9 | ||||
-rw-r--r-- | drivers/spi/Makefile | 1 | ||||
-rw-r--r-- | drivers/spi/armada100_spi.c | 228 | ||||
-rw-r--r-- | drivers/spi/kirkwood_spi.c | 5 | ||||
-rw-r--r-- | drivers/usb/host/ehci-kirkwood.c | 1 |
24 files changed, 1093 insertions, 406 deletions
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 9d945a0..3d9c9f1 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -27,6 +27,7 @@ LIB := $(obj)libdma.o COBJS-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o COBJS-$(CONFIG_FSL_DMA) += fsl_dma.o +COBJS-$(CONFIG_OMAP3_DMA) += omap3_dma.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/dma/omap3_dma.c b/drivers/dma/omap3_dma.c new file mode 100644 index 0000000..b98eca1 --- /dev/null +++ b/drivers/dma/omap3_dma.c @@ -0,0 +1,180 @@ +/* Copyright (C) 2011 + * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* This is a basic implementation of the SDMA/DMA4 controller of OMAP3 + * Tested on Silicon Revision major:0x4 minor:0x0 + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/omap3.h> +#include <asm/arch/dma.h> +#include <asm/io.h> +#include <asm/errno.h> + +static struct dma4 *dma4_cfg = (struct dma4 *)OMAP34XX_DMA4_BASE; +uint32_t dma_active; /* if a transfer is started the respective + bit is set for the logical channel */ + +/* Check if we have the given channel + * PARAMETERS: + * chan: Channel number + * + * RETURN of non-zero means error */ +static inline int check_channel(uint32_t chan) +{ + if (chan < CHAN_NR_MIN || chan > CHAN_NR_MAX) + return -EINVAL; + return 0; +} + +static inline void reset_irq(uint32_t chan) +{ + /* reset IRQ reason */ + writel(0x1DFE, &dma4_cfg->chan[chan].csr); + /* reset IRQ */ + writel((1 << chan), &dma4_cfg->irqstatus_l[0]); + dma_active &= ~(1 << chan); +} + +/* Set Source, Destination and Size of DMA transfer for the + * specified channel. + * PARAMETERS: + * chan: channel to use + * src: source of the transfer + * dst: destination of the transfer + * sze: Size of the transfer + * + * RETURN of non-zero means error */ +int omap3_dma_conf_transfer(uint32_t chan, uint32_t *src, uint32_t *dst, + uint32_t sze) +{ + if (check_channel(chan)) + return -EINVAL; + /* CDSA0 */ + writel((uint32_t)src, &dma4_cfg->chan[chan].cssa); + writel((uint32_t)dst, &dma4_cfg->chan[chan].cdsa); + writel(sze, &dma4_cfg->chan[chan].cen); +return 0; +} + +/* Start the DMA transfer */ +int omap3_dma_start_transfer(uint32_t chan) +{ + uint32_t val; + + if (check_channel(chan)) + return -EINVAL; + + val = readl(&dma4_cfg->chan[chan].ccr); + /* Test for channel already in use */ + if (val & CCR_ENABLE_ENABLE) + return -EBUSY; + + writel((val | CCR_ENABLE_ENABLE), &dma4_cfg->chan[chan].ccr); + dma_active |= (1 << chan); + debug("started transfer...\n"); + return 0; +} + +/* Busy-waiting for a DMA transfer + * This has to be called before another transfer is started + * PARAMETER + * chan: Channel to wait for + * + * RETURN of non-zero means error*/ +int omap3_dma_wait_for_transfer(uint32_t chan) +{ + uint32_t val; + + if (!(dma_active & (1 << chan))) { + val = readl(&dma4_cfg->irqstatus_l[0]); + if (!(val & chan)) { + debug("dma: The channel you are trying to wait for " + "was never activated - ERROR\n"); + return -1; /* channel was never active */ + } + } + + /* all irqs on line 0 */ + while (!(readl(&dma4_cfg->irqstatus_l[0]) & (1 << chan))) + asm("nop"); + + val = readl(&dma4_cfg->chan[chan].csr); + if ((val & CSR_TRANS_ERR) | (val & CSR_SUPERVISOR_ERR) | + (val & CSR_MISALIGNED_ADRS_ERR)) { + debug("err code: %X\n", val); + debug("dma: transfer error detected\n"); + reset_irq(chan); + return -1; + } + reset_irq(chan); + return 0; +} + +/* Get the revision of the DMA module + * PARAMETER + * minor: Address of minor revision to write + * major: Address of major revision to write + * + * RETURN of non-zero means error + */ +int omap3_dma_get_revision(uint32_t *minor, uint32_t *major) +{ + uint32_t val; + + /* debug information */ + val = readl(&dma4_cfg->revision); + *major = (val & 0x000000F0) >> 4; + *minor = (val & 0x0000000F); + debug("DMA Silicon revision (maj/min): 0x%X/0x%X\n", *major, *minor); + return 0; +} + +/* Initial config of omap dma + */ +void omap3_dma_init(void) +{ + dma_active = 0; + /* All interrupts on channel 0 */ + writel(0xFFFFFFFF, &dma4_cfg->irqenable_l[0]); +} + +/* set channel config to config + * + * RETURN of non-zero means error */ +int omap3_dma_conf_chan(uint32_t chan, struct dma4_chan *config) +{ + if (check_channel(chan)) + return -EINVAL; + + dma4_cfg->chan[chan] = *config; + return 0; +} + +/* get channel config to config + * + * RETURN of non-zero means error */ +int omap3_dma_get_conf_chan(uint32_t chan, struct dma4_chan *config) +{ + if (check_channel(chan)) + return -EINVAL; + *config = dma4_cfg->chan[chan]; + return 0; +} diff --git a/drivers/gpio/kw_gpio.c b/drivers/gpio/kw_gpio.c index 2de179e..51a826d 100644 --- a/drivers/gpio/kw_gpio.c +++ b/drivers/gpio/kw_gpio.c @@ -31,6 +31,7 @@ #include <common.h> #include <asm/bitops.h> +#include <asm/io.h> #include <asm/arch/kirkwood.h> #include <asm/arch/gpio.h> diff --git a/drivers/gpio/mvmfp.c b/drivers/gpio/mvmfp.c index e7830c6..f56c037 100644 --- a/drivers/gpio/mvmfp.c +++ b/drivers/gpio/mvmfp.c @@ -26,13 +26,6 @@ #include <asm/io.h> #include <mvmfp.h> #include <asm/arch/mfp.h> -#ifdef CONFIG_ARMADA100 -#include <asm/arch/armada100.h> -#elif defined(CONFIG_PANTHEON) -#include <asm/arch/pantheon.h> -#else -#error Unsupported SoC... -#endif /* * mfp_config diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index a805bf6..2869d7c 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -95,7 +95,7 @@ static u16 i2c_clk_div[50][2] = { { 3072, 0x1E }, { 3840, 0x1F } }; -static u8 clk_idx; +static u8 clk_div; /* * Calculate and set proper clock divider @@ -105,7 +105,6 @@ static void i2c_imx_set_clk(unsigned int rate) struct mxc_i2c_regs *i2c_regs = (struct mxc_i2c_regs *)I2C_BASE; unsigned int i2c_clk_rate; unsigned int div; - int i; #if defined(CONFIG_MX31) struct clock_control_regs *sc_regs = @@ -120,16 +119,15 @@ static void i2c_imx_set_clk(unsigned int rate) i2c_clk_rate = mxc_get_clock(MXC_IPG_PERCLK); div = (i2c_clk_rate + rate - 1) / rate; if (div < i2c_clk_div[0][0]) - i = 0; + clk_div = 0; else if (div > i2c_clk_div[ARRAY_SIZE(i2c_clk_div) - 1][0]) - i = ARRAY_SIZE(i2c_clk_div) - 1; + clk_div = ARRAY_SIZE(i2c_clk_div) - 1; else - for (i = 0; i2c_clk_div[i][0] < div; i++) + for (clk_div = 0; i2c_clk_div[clk_div][0] < div; clk_div++) ; /* Store divider value */ - clk_idx = i2c_clk_div[i][1]; - writeb(clk_idx, &i2c_regs->ifdr); + writeb(i2c_clk_div[clk_div][1], &i2c_regs->ifdr); } /* @@ -153,6 +151,23 @@ void i2c_init(int speed, int unused) } /* + * Set I2C Speed + */ +int i2c_set_bus_speed(unsigned int speed) +{ + i2c_init(speed, 0); + return 0; +} + +/* + * Get I2C Speed + */ +unsigned int i2c_get_bus_speed(void) +{ + return mxc_get_clock(MXC_IPG_PERCLK) / i2c_clk_div[clk_div][0]; +} + +/* * Wait for bus to be busy (or free if for_busy = 0) * * for_busy = 1: Wait for IBB to be asserted @@ -218,7 +233,7 @@ int i2c_imx_start(void) unsigned int temp = 0; int result; - writeb(clk_idx, &i2c_regs->ifdr); + writeb(i2c_clk_div[clk_div][1], &i2c_regs->ifdr); /* Enable I2C controller */ writeb(0, &i2c_regs->i2sr); diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index b152486..a709707 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -28,13 +28,17 @@ LIB := $(obj)libmisc.o COBJS-$(CONFIG_ALI152X) += ali512x.o COBJS-$(CONFIG_DS4510) += ds4510.o COBJS-$(CONFIG_FSL_LAW) += fsl_law.o -COBJS-$(CONFIG_FSL_PMIC) += fsl_pmic.o COBJS-$(CONFIG_GPIO_LED) += gpio_led.o COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o COBJS-$(CONFIG_NS87308) += ns87308.o COBJS-$(CONFIG_PDSP188x) += pdsp188x.o COBJS-$(CONFIG_STATUS_LED) += status_led.o COBJS-$(CONFIG_TWL4030_LED) += twl4030_led.o +COBJS-$(CONFIG_PMIC) += pmic_core.o +COBJS-$(CONFIG_PMIC_FSL) += pmic_fsl.o +COBJS-$(CONFIG_PMIC_I2C) += pmic_i2c.o +COBJS-$(CONFIG_PMIC_SPI) += pmic_spi.o +COBJS-$(CONFIG_PMIC_MAX8998) += pmic_max8998.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/misc/fsl_pmic.c b/drivers/misc/fsl_pmic.c deleted file mode 100644 index 23255a5..0000000 --- a/drivers/misc/fsl_pmic.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * (C) Copyright 2008-2009 Freescale Semiconductor, Inc. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include <config.h> -#include <common.h> -#include <asm/errno.h> -#include <linux/types.h> -#include <fsl_pmic.h> - -static int check_param(u32 reg, u32 write) -{ - if (reg > 63 || write > 1) { - printf("<reg num> = %d is invalid. Should be less then 63\n", - reg); - return -1; - } - - return 0; -} - -#ifdef CONFIG_FSL_PMIC_I2C -#include <i2c.h> - -u32 pmic_reg(u32 reg, u32 val, u32 write) -{ - unsigned char buf[4] = { 0 }; - u32 ret_val = 0; - - if (check_param(reg, write)) - return -1; - - if (write) { - buf[0] = (val >> 16) & 0xff; - buf[1] = (val >> 8) & 0xff; - buf[2] = (val) & 0xff; - if (i2c_write(CONFIG_SYS_FSL_PMIC_I2C_ADDR, reg, 1, buf, 3)) - return -1; - } else { - if (i2c_read(CONFIG_SYS_FSL_PMIC_I2C_ADDR, reg, 1, buf, 3)) - return -1; - ret_val = buf[0] << 16 | buf[1] << 8 | buf[2]; - } - - return ret_val; -} -#else /* SPI interface */ -#include <spi.h> -static struct spi_slave *slave; - -struct spi_slave *pmic_spi_probe(void) -{ - return spi_setup_slave(CONFIG_FSL_PMIC_BUS, - CONFIG_FSL_PMIC_CS, - CONFIG_FSL_PMIC_CLK, - CONFIG_FSL_PMIC_MODE); -} - -void pmic_spi_free(struct spi_slave *slave) -{ - if (slave) - spi_free_slave(slave); -} - -u32 pmic_reg(u32 reg, u32 val, u32 write) -{ - u32 pmic_tx, pmic_rx; - u32 tmp; - - if (!slave) { - slave = pmic_spi_probe(); - - if (!slave) - return -1; - } - - if (check_param(reg, write)) - return -1; - - if (spi_claim_bus(slave)) - return -1; - - pmic_tx = (write << 31) | (reg << 25) | (val & 0x00FFFFFF); - - tmp = cpu_to_be32(pmic_tx); - - if (spi_xfer(slave, 4 << 3, &tmp, &pmic_rx, - SPI_XFER_BEGIN | SPI_XFER_END)) { - spi_release_bus(slave); - return -1; - } - - if (write) { - pmic_tx &= ~(1 << 31); - tmp = cpu_to_be32(pmic_tx); - if (spi_xfer(slave, 4 << 3, &tmp, &pmic_rx, - SPI_XFER_BEGIN | SPI_XFER_END)) { - spi_release_bus(slave); - return -1; - } - } - - spi_release_bus(slave); - return cpu_to_be32(pmic_rx); -} -#endif - -void pmic_reg_write(u32 reg, u32 value) -{ - pmic_reg(reg, value, 1); -} - -u32 pmic_reg_read(u32 reg) -{ - return pmic_reg(reg, 0, 0); -} - -void pmic_show_pmic_info(void) -{ - u32 rev_id; - - rev_id = pmic_reg_read(REG_IDENTIFICATION); - printf("PMIC ID: 0x%08x [Rev: ", rev_id); - switch (rev_id & 0x1F) { - case 0x1: - puts("1.0"); - break; - case 0x9: - puts("1.1"); - break; - case 0xA: - puts("1.2"); - break; - case 0x10: - puts("2.0"); - break; - case 0x11: - puts("2.1"); - break; - case 0x18: - puts("3.0"); - break; - case 0x19: - puts("3.1"); - break; - case 0x1A: - puts("3.2"); - break; - case 0x2: - puts("3.2A"); - break; - case 0x1B: - puts("3.3"); - break; - case 0x1D: - puts("3.5"); - break; - default: - puts("unknown"); - break; - } - puts("]\n"); -} - -static void pmic_dump(int numregs) -{ - u32 val; - int i; - - pmic_show_pmic_info(); - for (i = 0; i < numregs; i++) { - val = pmic_reg_read(i); - if (!(i % 8)) - printf ("\n0x%02x: ", i); - printf("%08x ", val); - } - puts("\n"); -} - -int do_pmic(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) -{ - char *cmd; - int nregs; - u32 val; - - /* at least two arguments please */ - if (argc < 2) - return cmd_usage(cmdtp); - - cmd = argv[1]; - if (strcmp(cmd, "dump") == 0) { - if (argc < 3) - return cmd_usage(cmdtp); - - nregs = simple_strtoul(argv[2], NULL, 16); - pmic_dump(nregs); - return 0; - } - if (strcmp(cmd, "write") == 0) { - if (argc < 4) - return cmd_usage(cmdtp); - - nregs = simple_strtoul(argv[2], NULL, 16); - val = simple_strtoul(argv[3], NULL, 16); - pmic_reg_write(nregs, val); - return 0; - } - /* No subcommand found */ - return 1; -} - -U_BOOT_CMD( - pmic, CONFIG_SYS_MAXARGS, 1, do_pmic, - "Freescale PMIC (Atlas)", - "dump [numregs] - dump registers\n" - "pmic write <reg> <value> - write register" -); diff --git a/drivers/misc/pmic_core.c b/drivers/misc/pmic_core.c new file mode 100644 index 0000000..5d62a56 --- /dev/null +++ b/drivers/misc/pmic_core.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * Lukasz Majewski <l.majewski@samsung.com> + * + * (C) Copyright 2010 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de + * + * (C) Copyright 2008-2009 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <linux/types.h> +#include <pmic.h> + +static struct pmic pmic; + +int check_reg(u32 reg) +{ + if (reg >= pmic.number_of_regs) { + printf("<reg num> = %d is invalid. Should be less than %d\n", + reg, pmic.number_of_regs); + return -1; + } + return 0; +} + +int pmic_set_output(struct pmic *p, u32 reg, int out, int on) +{ + u32 val; + + if (pmic_reg_read(p, reg, &val)) + return -1; + + if (on) + val |= out; + else + val &= ~out; + + if (pmic_reg_write(p, reg, val)) + return -1; + + return 0; +} + +static void pmic_show_info(struct pmic *p) +{ + printf("PMIC: %s\n", p->name); +} + +static void pmic_dump(struct pmic *p) +{ + int i, ret; + u32 val; + + pmic_show_info(p); + for (i = 0; i < p->number_of_regs; i++) { + ret = pmic_reg_read(p, i, &val); + if (ret) + puts("PMIC: Registers dump failed\n"); + + if (!(i % 8)) + printf("\n0x%02x: ", i); + + printf("%08x ", val); + } + puts("\n"); +} + +struct pmic *get_pmic(void) +{ + return &pmic; +} + +int do_pmic(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + u32 ret, reg, val; + char *cmd; + + struct pmic *p = &pmic; + + /* at least two arguments please */ + if (argc < 2) + return cmd_usage(cmdtp); + + cmd = argv[1]; + if (strcmp(cmd, "dump") == 0) { + pmic_dump(p); + return 0; + } + + if (strcmp(cmd, "read") == 0) { + if (argc < 3) + return cmd_usage(cmdtp); + + reg = simple_strtoul(argv[2], NULL, 16); + + ret = pmic_reg_read(p, reg, &val); + + if (ret) + puts("PMIC: Register read failed\n"); + + printf("\n0x%02x: 0x%08x\n", reg, val); + + return 0; + } + + if (strcmp(cmd, "write") == 0) { + if (argc < 4) + return cmd_usage(cmdtp); + + reg = simple_strtoul(argv[2], NULL, 16); + val = simple_strtoul(argv[3], NULL, 16); + + pmic_reg_write(p, reg, val); + + return 0; + } + + /* No subcommand found */ + return 1; +} + +U_BOOT_CMD( + pmic, CONFIG_SYS_MAXARGS, 1, do_pmic, + "PMIC", + "dump - dump PMIC registers\n" + "pmic read <reg> - read register\n" + "pmic write <reg> <value> - write register" +); diff --git a/drivers/misc/pmic_fsl.c b/drivers/misc/pmic_fsl.c new file mode 100644 index 0000000..b6e809a --- /dev/null +++ b/drivers/misc/pmic_fsl.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * Lukasz Majewski <l.majewski@samsung.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <spi.h> +#include <pmic.h> +#include <fsl_pmic.h> + +#if defined(CONFIG_PMIC_SPI) +static u32 pmic_spi_prepare_tx(u32 reg, u32 *val, u32 write) +{ + if ((val == NULL) && (write)) + return *val & ~(1 << 31); + else + return (write << 31) | (reg << 25) | (*val & 0x00FFFFFF); +} +#endif + +int pmic_init(void) +{ + struct pmic *p = get_pmic(); + static const char name[] = "FSL_PMIC"; + + p->name = name; + p->number_of_regs = PMIC_NUM_OF_REGS; + +#if defined(CONFIG_PMIC_SPI) + p->interface = PMIC_SPI; + p->bus = CONFIG_FSL_PMIC_BUS; + p->hw.spi.cs = CONFIG_FSL_PMIC_CS; + p->hw.spi.clk = CONFIG_FSL_PMIC_CLK; + p->hw.spi.mode = CONFIG_FSL_PMIC_MODE; + p->hw.spi.bitlen = CONFIG_FSL_PMIC_BITLEN; + p->hw.spi.flags = SPI_XFER_BEGIN | SPI_XFER_END; + p->hw.spi.prepare_tx = pmic_spi_prepare_tx; +#elif defined(CONFIG_PMIC_I2C) + p->interface = PMIC_I2C; + p->hw.i2c.addr = CONFIG_SYS_FSL_PMIC_I2C_ADDR; + p->hw.i2c.tx_num = 3; + p->bus = I2C_PMIC; +#else +#error "You must select CONFIG_PMIC_SPI or CONFIG_PMIC_I2C" +#endif + + return 0; +} diff --git a/drivers/misc/pmic_i2c.c b/drivers/misc/pmic_i2c.c new file mode 100644 index 0000000..ad55d64 --- /dev/null +++ b/drivers/misc/pmic_i2c.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * Lukasz Majewski <l.majewski@samsung.com> + * + * (C) Copyright 2010 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de + * + * (C) Copyright 2008-2009 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <linux/types.h> +#include <pmic.h> +#include <i2c.h> + +int pmic_reg_write(struct pmic *p, u32 reg, u32 val) +{ + unsigned char buf[4] = { 0 }; + + if (check_reg(reg)) + return -1; + + switch (pmic_i2c_tx_num) { + case 3: + buf[0] = (val >> 16) & 0xff; + buf[1] = (val >> 8) & 0xff; + buf[2] = val & 0xff; + break; + case 1: + buf[0] = val & 0xff; + break; + } + + if (i2c_write(pmic_i2c_addr, reg, 1, buf, pmic_i2c_tx_num)) + return -1; + + return 0; +} + +int pmic_reg_read(struct pmic *p, u32 reg, u32 *val) +{ + unsigned char buf[4] = { 0 }; + u32 ret_val = 0; + + if (check_reg(reg)) + return -1; + + if (i2c_read(pmic_i2c_addr, reg, 1, buf, pmic_i2c_tx_num)) + return -1; + + switch (pmic_i2c_tx_num) { + case 3: + ret_val = buf[0] << 16 | buf[1] << 8 | buf[2]; + break; + case 1: + ret_val = buf[0]; + break; + } + memcpy(val, &ret_val, sizeof(ret_val)); + + return 0; +} + +int pmic_probe(struct pmic *p) +{ + I2C_SET_BUS(p->bus); + debug("PMIC:%s probed!\n", p->name); + if (i2c_probe(pmic_i2c_addr)) { + printf("Can't find PMIC:%s\n", p->name); + return -1; + } + + return 0; +} diff --git a/drivers/misc/pmic_max8998.c b/drivers/misc/pmic_max8998.c new file mode 100644 index 0000000..cc69fd7 --- /dev/null +++ b/drivers/misc/pmic_max8998.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * Lukasz Majewski <l.majewski@samsung.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <pmic.h> +#include <max8998_pmic.h> + +int pmic_init(void) +{ + struct pmic *p = get_pmic(); + static const char name[] = "MAX8998_PMIC"; + + puts("Board PMIC init\n"); + + p->name = name; + p->interface = PMIC_I2C; + p->number_of_regs = PMIC_NUM_OF_REGS; + p->hw.i2c.addr = MAX8998_I2C_ADDR; + p->hw.i2c.tx_num = 1; + p->bus = I2C_PMIC; + + return 0; +} diff --git a/drivers/misc/pmic_spi.c b/drivers/misc/pmic_spi.c new file mode 100644 index 0000000..ff35377 --- /dev/null +++ b/drivers/misc/pmic_spi.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * Lukasz Majewski <l.majewski@samsung.com> + * + * (C) Copyright 2010 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de + * + * (C) Copyright 2008-2009 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <linux/types.h> +#include <pmic.h> +#include <spi.h> + +static struct spi_slave *slave; + +void pmic_spi_free(struct spi_slave *slave) +{ + if (slave) + spi_free_slave(slave); +} + +struct spi_slave *pmic_spi_probe(struct pmic *p) +{ + return spi_setup_slave(p->bus, + p->hw.spi.cs, + p->hw.spi.clk, + p->hw.spi.mode); +} + +static u32 pmic_reg(struct pmic *p, u32 reg, u32 *val, u32 write) +{ + u32 pmic_tx, pmic_rx; + u32 tmp; + + if (!slave) { + slave = pmic_spi_probe(p); + + if (!slave) + return -1; + } + + if (check_reg(reg)) + return -1; + + if (spi_claim_bus(slave)) + return -1; + + pmic_tx = p->hw.spi.prepare_tx(reg, val, write); + + tmp = cpu_to_be32(pmic_tx); + + if (spi_xfer(slave, pmic_spi_bitlen, &tmp, &pmic_rx, + pmic_spi_flags)) { + spi_release_bus(slave); + return -1; + } + + if (write) { + pmic_tx = p->hw.spi.prepare_tx(0, NULL, write); + pmic_tx &= ~(1 << 31); + tmp = cpu_to_be32(pmic_tx); + if (spi_xfer(slave, pmic_spi_bitlen, &tmp, &pmic_rx, + pmic_spi_flags)) { + spi_release_bus(slave); + return -1; + } + } + + spi_release_bus(slave); + *val = cpu_to_be32(pmic_rx); + + return 0; +} + +int pmic_reg_write(struct pmic *p, u32 reg, u32 val) +{ + if (pmic_reg(p, reg, &val, 1)) + return -1; + + return 0; +} + +int pmic_reg_read(struct pmic *p, u32 reg, u32 *val) +{ + if (pmic_reg(p, reg, val, 0)) + return -1; + + return 0; +} diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 5d4cf51..ebda980 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -475,12 +475,16 @@ int omap_mmc_init(int dev_index) case 0: mmc->priv = (hsmmc_t *)OMAP_HSMMC1_BASE; break; +#ifdef OMAP_HSMMC2_BASE case 1: mmc->priv = (hsmmc_t *)OMAP_HSMMC2_BASE; break; +#endif +#ifdef OMAP_HSMMC3_BASE case 2: mmc->priv = (hsmmc_t *)OMAP_HSMMC3_BASE; break; +#endif default: mmc->priv = (hsmmc_t *)OMAP_HSMMC1_BASE; return 1; diff --git a/drivers/mmc/tegra2_mmc.c b/drivers/mmc/tegra2_mmc.c index 8b6f829..9e741f2 100644 --- a/drivers/mmc/tegra2_mmc.c +++ b/drivers/mmc/tegra2_mmc.c @@ -23,36 +23,46 @@ #include <mmc.h> #include <asm/io.h> #include <asm/arch/clk_rst.h> +#include <asm/arch/clock.h> #include "tegra2_mmc.h" /* support 4 mmc hosts */ struct mmc mmc_dev[4]; struct mmc_host mmc_host[4]; -static inline struct tegra2_mmc *tegra2_get_base_mmc(int dev_index) + +/** + * Get the host address and peripheral ID for a device. Devices are numbered + * from 0 to 3. + * + * @param host Structure to fill in (base, reg, mmc_id) + * @param dev_index Device index (0-3) + */ +static void tegra2_get_setup(struct mmc_host *host, int dev_index) { - unsigned long offset; debug("tegra2_get_base_mmc: dev_index = %d\n", dev_index); switch (dev_index) { - case 0: - offset = TEGRA2_SDMMC4_BASE; - break; case 1: - offset = TEGRA2_SDMMC3_BASE; + host->base = TEGRA2_SDMMC3_BASE; + host->mmc_id = PERIPH_ID_SDMMC3; break; case 2: - offset = TEGRA2_SDMMC2_BASE; + host->base = TEGRA2_SDMMC2_BASE; + host->mmc_id = PERIPH_ID_SDMMC2; break; case 3: - offset = TEGRA2_SDMMC1_BASE; + host->base = TEGRA2_SDMMC1_BASE; + host->mmc_id = PERIPH_ID_SDMMC1; break; + case 0: default: - offset = TEGRA2_SDMMC4_BASE; + host->base = TEGRA2_SDMMC4_BASE; + host->mmc_id = PERIPH_ID_SDMMC4; break; } - return (struct tegra2_mmc *)(offset); + host->reg = (struct tegra2_mmc *)host->base; } static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data) @@ -274,62 +284,24 @@ static int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, static void mmc_change_clock(struct mmc_host *host, uint clock) { - int div, hw_div; + int div; unsigned short clk; unsigned long timeout; - unsigned int reg, hostbase; - struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + debug(" mmc_change_clock called\n"); - /* Change Tegra2 SDMMCx clock divisor here */ - /* Source is 216MHz, PLLP_OUT0 */ + /* + * Change Tegra2 SDMMCx clock divisor here. Source is 216MHz, + * PLLP_OUT0 + */ if (clock == 0) goto out; - - div = 1; - if (clock <= 400000) { - hw_div = ((9-1)<<1); /* Best match is 375KHz */ - div = 64; - } else if (clock <= 20000000) - hw_div = ((11-1)<<1); /* Best match is 19.6MHz */ - else if (clock <= 26000000) - hw_div = ((9-1)<<1); /* Use 24MHz */ - else - hw_div = ((4-1)<<1) + 1; /* 4.5 divisor for 48MHz */ - - debug("mmc_change_clock: hw_div = %d, card clock div = %d\n", - hw_div, div); - - /* Change SDMMCx divisor */ - - hostbase = readl(&host->base); - debug("mmc_change_clock: hostbase = %08X\n", hostbase); - - if (hostbase == TEGRA2_SDMMC1_BASE) { - reg = readl(&clkrst->crc_clk_src_sdmmc1); - reg &= 0xFFFFFF00; /* divisor (7.1) = 00 */ - reg |= hw_div; /* n-1 */ - writel(reg, &clkrst->crc_clk_src_sdmmc1); - } else if (hostbase == TEGRA2_SDMMC2_BASE) { - reg = readl(&clkrst->crc_clk_src_sdmmc2); - reg &= 0xFFFFFF00; /* divisor (7.1) = 00 */ - reg |= hw_div; /* n-1 */ - writel(reg, &clkrst->crc_clk_src_sdmmc2); - } else if (hostbase == TEGRA2_SDMMC3_BASE) { - reg = readl(&clkrst->crc_clk_src_sdmmc3); - reg &= 0xFFFFFF00; /* divisor (7.1) = 00 */ - reg |= hw_div; /* n-1 */ - writel(reg, &clkrst->crc_clk_src_sdmmc3); - } else { - reg = readl(&clkrst->crc_clk_src_sdmmc4); - reg &= 0xFFFFFF00; /* divisor (7.1) = 00 */ - reg |= hw_div; /* n-1 */ - writel(reg, &clkrst->crc_clk_src_sdmmc4); - } + clock_adjust_periph_pll_div(host->mmc_id, CLOCK_ID_PERIPH, clock, + &div); + debug("div = %d\n", div); writew(0, &host->reg->clkcon); - div >>= 1; /* * CLKCON * SELFREQ[15:8] : base clock divided by value @@ -337,6 +309,7 @@ static void mmc_change_clock(struct mmc_host *host, uint clock) * STBLINTCLK[1] : Internal Clock Stable * ENINTCLK[0] : Internal Clock Enable */ + div >>= 1; clk = (div << 8) | (1 << 0); writew(clk, &host->reg->clkcon); @@ -355,7 +328,6 @@ static void mmc_change_clock(struct mmc_host *host, uint clock) writew(clk, &host->reg->clkcon); debug("mmc_change_clock: clkcon = %08X\n", clk); - debug("mmc_change_clock: CLK_SOURCE_SDMMCx = %08X\n", reg); out: host->clock = clock; @@ -370,7 +342,6 @@ static void mmc_set_ios(struct mmc *mmc) debug("bus_width: %x, clock: %d\n", mmc->bus_width, mmc->clock); /* Change clock first */ - mmc_change_clock(host, mmc->clock); ctrl = readb(&host->reg->hostctl); @@ -481,7 +452,7 @@ static int tegra2_mmc_initialize(int dev_index, int bus_width) mmc->host_caps = MMC_MODE_8BIT; else mmc->host_caps = MMC_MODE_4BIT; - mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + mmc->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_HC; /* * min freq is for card identification, and is the highest @@ -495,8 +466,7 @@ static int tegra2_mmc_initialize(int dev_index, int bus_width) mmc->f_max = 48000000; mmc_host[dev_index].clock = 0; - mmc_host[dev_index].reg = tegra2_get_base_mmc(dev_index); - mmc_host[dev_index].base = (unsigned int)mmc_host[dev_index].reg; + tegra2_get_setup(&mmc_host[dev_index], dev_index); mmc_register(mmc); return 0; diff --git a/drivers/mmc/tegra2_mmc.h b/drivers/mmc/tegra2_mmc.h index 4b80f9f..28698e0 100644 --- a/drivers/mmc/tegra2_mmc.h +++ b/drivers/mmc/tegra2_mmc.h @@ -73,6 +73,7 @@ struct mmc_host { unsigned int version; /* SDHCI spec. version */ unsigned int clock; /* Current clock (MHz) */ unsigned int base; /* Base address, SDMMC1/2/3/4 */ + enum periph_id mmc_id; /* Peripheral ID: PERIPH_ID_... */ }; int tegra2_mmc_init(int dev_index, int bus_width); diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index a8905b8..7dacb23 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -48,9 +48,9 @@ unsigned int emac_dbg = 0; #define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args) #ifdef DAVINCI_EMAC_GIG_ENABLE -#define emac_gigabit_enable() davinci_eth_gigabit_enable() +#define emac_gigabit_enable(phy_addr) davinci_eth_gigabit_enable(phy_addr) #else -#define emac_gigabit_enable() /* no gigabit to enable */ +#define emac_gigabit_enable(phy_addr) /* no gigabit to enable */ #endif static void davinci_eth_mdio_enable(void); @@ -80,10 +80,15 @@ static int emac_rx_queue_active = 0; /* Receive packet buffers */ static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; +#define MAX_PHY 3 + /* PHY address for a discovered PHY (0xff - not found) */ -static volatile u_int8_t active_phy_addr = 0xff; +static u_int8_t active_phy_addr[MAX_PHY] = { 0xff, 0xff, 0xff }; + +/* number of PHY found active */ +static u_int8_t num_phy; -phy_t phy; +phy_t phy[MAX_PHY]; static int davinci_eth_set_mac_addr(struct eth_device *dev) { @@ -147,27 +152,30 @@ static int davinci_eth_phy_detect(void) { u_int32_t phy_act_state; int i; + int j; + unsigned int count = 0; - active_phy_addr = 0xff; + active_phy_addr[0] = 0xff; + active_phy_addr[1] = 0xff; + active_phy_addr[2] = 0xff; + + udelay(1000); + phy_act_state = readl(&adap_mdio->ALIVE); - phy_act_state = readl(&adap_mdio->ALIVE) & EMAC_MDIO_PHY_MASK; if (phy_act_state == 0) - return(0); /* No active PHYs */ + return 0; /* No active PHYs */ debug_emac("davinci_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state); - for (i = 0; i < 32; i++) { + for (i = 0, j = 0; i < 32; i++) if (phy_act_state & (1 << i)) { - if (phy_act_state & ~(1 << i)) - return(0); /* More than one PHY */ - else { - active_phy_addr = i; - return(1); - } + count++; + active_phy_addr[j++] = i; } - } - return(0); /* Just to make GCC happy */ + num_phy = count; + + return count; } @@ -236,7 +244,18 @@ static int gen_is_phy_connected(int phy_addr) { u_int16_t dummy; - return(davinci_eth_phy_read(phy_addr, MII_PHYSID1, &dummy)); + return davinci_eth_phy_read(phy_addr, MII_PHYSID1, &dummy); +} + +static int get_active_phy(void) +{ + int i; + + for (i = 0; i < num_phy; i++) + if (phy[i].get_link_speed(active_phy_addr[i])) + return i; + + return -1; /* Return error if no link */ } static int gen_get_link_speed(int phy_addr) @@ -279,16 +298,42 @@ static int gen_get_link_speed(int phy_addr) static int gen_auto_negotiate(int phy_addr) { u_int16_t tmp; + u_int16_t val; + unsigned long cntr = 0; + + if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &tmp)) + return 0; + + val = tmp | BMCR_FULLDPLX | BMCR_ANENABLE | + BMCR_SPEED100; + davinci_eth_phy_write(phy_addr, MII_BMCR, val); + + if (!davinci_eth_phy_read(phy_addr, MII_ADVERTISE, &val)) + return 0; + + val |= (ADVERTISE_100FULL | ADVERTISE_100HALF | ADVERTISE_10FULL | + ADVERTISE_10HALF); + davinci_eth_phy_write(phy_addr, MII_ADVERTISE, val); if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &tmp)) return(0); /* Restart Auto_negotiation */ - tmp |= BMCR_ANENABLE; + tmp |= BMCR_ANRESTART; davinci_eth_phy_write(phy_addr, MII_BMCR, tmp); /*check AutoNegotiate complete */ - udelay (10000); + do { + udelay(40000); + if (!davinci_eth_phy_read(phy_addr, MII_BMSR, &tmp)) + return 0; + + if (tmp & BMSR_ANEGCOMPLETE) + break; + + cntr++; + } while (cntr < 200); + if (!davinci_eth_phy_read(phy_addr, MII_BMSR, &tmp)) return(0); @@ -312,11 +357,11 @@ static int davinci_mii_phy_write(const char *devname, unsigned char addr, unsign } #endif -static void __attribute__((unused)) davinci_eth_gigabit_enable(void) +static void __attribute__((unused)) davinci_eth_gigabit_enable(int phy_addr) { u_int16_t data; - if (davinci_eth_phy_read(EMAC_MDIO_PHY_NUM, 0, &data)) { + if (davinci_eth_phy_read(phy_addr, 0, &data)) { if (data & (1 << 6)) { /* speed selection MSB */ /* * Check if link detected is giga-bit @@ -336,6 +381,7 @@ static int davinci_eth_open(struct eth_device *dev, bd_t *bis) dv_reg_p addr; u_int32_t clkdiv, cnt; volatile emac_desc *rx_desc; + int index; debug_emac("+ emac_open\n"); @@ -434,10 +480,11 @@ static int davinci_eth_open(struct eth_device *dev, bd_t *bis) /* We need to wait for MDIO to start */ udelay(1000); - if (!phy.get_link_speed(active_phy_addr)) + index = get_active_phy(); + if (index == -1) return(0); - emac_gigabit_enable(); + emac_gigabit_enable(active_phy_addr[index]); /* Start receive process */ writel((u_int32_t)emac_rx_desc, &adap_emac->RX0HDP); @@ -533,16 +580,16 @@ static int davinci_eth_send_packet (struct eth_device *dev, volatile void *packet, int length) { int ret_status = -1; - + int index; tx_send_loop = 0; - /* Return error if no link */ - if (!phy.get_link_speed (active_phy_addr)) { - printf ("WARN: emac_send_packet: No link\n"); + index = get_active_phy(); + if (index == -1) { + printf(" WARN: emac_send_packet: No link\n"); return (ret_status); } - emac_gigabit_enable(); + emac_gigabit_enable(active_phy_addr[index]); /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */ if (length < EMAC_MIN_ETHERNET_PKT_SIZE) { @@ -562,12 +609,12 @@ static int davinci_eth_send_packet (struct eth_device *dev, /* Wait for packet to complete or link down */ while (1) { - if (!phy.get_link_speed (active_phy_addr)) { + if (!phy[index].get_link_speed(active_phy_addr[index])) { davinci_eth_ch_teardown (EMAC_CH_TX); return (ret_status); } - emac_gigabit_enable(); + emac_gigabit_enable(active_phy_addr[index]); if (readl(&adap_emac->TXINTSTATRAW) & 0x01) { ret_status = length; @@ -659,6 +706,7 @@ int davinci_emac_initialize(void) u_int32_t phy_id; u_int16_t tmp; int i; + int ret; struct eth_device *dev; dev = malloc(sizeof *dev); @@ -686,7 +734,7 @@ int davinci_emac_initialize(void) for (i = 0; i < 256; i++) { if (readl(&adap_mdio->ALIVE)) break; - udelay(10); + udelay(1000); } if (i >= 256) { @@ -694,64 +742,77 @@ int davinci_emac_initialize(void) return(0); } - /* Find if a PHY is connected and get it's address */ - if (!davinci_eth_phy_detect()) + /* Find if PHY(s) is/are connected */ + ret = davinci_eth_phy_detect(); + if (!ret) return(0); + else + printf(" %d ETH PHY detected\n", ret); /* Get PHY ID and initialize phy_ops for a detected PHY */ - if (!davinci_eth_phy_read(active_phy_addr, MII_PHYSID1, &tmp)) { - active_phy_addr = 0xff; - return(0); - } + for (i = 0; i < num_phy; i++) { + if (!davinci_eth_phy_read(active_phy_addr[i], MII_PHYSID1, + &tmp)) { + active_phy_addr[i] = 0xff; + continue; + } - phy_id = (tmp << 16) & 0xffff0000; + phy_id = (tmp << 16) & 0xffff0000; - if (!davinci_eth_phy_read(active_phy_addr, MII_PHYSID2, &tmp)) { - active_phy_addr = 0xff; - return(0); - } + if (!davinci_eth_phy_read(active_phy_addr[i], MII_PHYSID2, + &tmp)) { + active_phy_addr[i] = 0xff; + continue; + } - phy_id |= tmp & 0x0000ffff; + phy_id |= tmp & 0x0000ffff; - switch (phy_id) { - case PHY_KSZ8873: - sprintf(phy.name, "KSZ8873 @ 0x%02x", active_phy_addr); - phy.init = ksz8873_init_phy; - phy.is_phy_connected = ksz8873_is_phy_connected; - phy.get_link_speed = ksz8873_get_link_speed; - phy.auto_negotiate = ksz8873_auto_negotiate; - break; + switch (phy_id) { + case PHY_KSZ8873: + sprintf(phy[i].name, "KSZ8873 @ 0x%02x", + active_phy_addr[i]); + phy[i].init = ksz8873_init_phy; + phy[i].is_phy_connected = ksz8873_is_phy_connected; + phy[i].get_link_speed = ksz8873_get_link_speed; + phy[i].auto_negotiate = ksz8873_auto_negotiate; + break; case PHY_LXT972: - sprintf(phy.name, "LXT972 @ 0x%02x", active_phy_addr); - phy.init = lxt972_init_phy; - phy.is_phy_connected = lxt972_is_phy_connected; - phy.get_link_speed = lxt972_get_link_speed; - phy.auto_negotiate = lxt972_auto_negotiate; + sprintf(phy[i].name, "LXT972 @ 0x%02x", + active_phy_addr[i]); + phy[i].init = lxt972_init_phy; + phy[i].is_phy_connected = lxt972_is_phy_connected; + phy[i].get_link_speed = lxt972_get_link_speed; + phy[i].auto_negotiate = lxt972_auto_negotiate; break; case PHY_DP83848: - sprintf(phy.name, "DP83848 @ 0x%02x", active_phy_addr); - phy.init = dp83848_init_phy; - phy.is_phy_connected = dp83848_is_phy_connected; - phy.get_link_speed = dp83848_get_link_speed; - phy.auto_negotiate = dp83848_auto_negotiate; + sprintf(phy[i].name, "DP83848 @ 0x%02x", + active_phy_addr[i]); + phy[i].init = dp83848_init_phy; + phy[i].is_phy_connected = dp83848_is_phy_connected; + phy[i].get_link_speed = dp83848_get_link_speed; + phy[i].auto_negotiate = dp83848_auto_negotiate; break; case PHY_ET1011C: - sprintf(phy.name, "ET1011C @ 0x%02x", active_phy_addr); - phy.init = gen_init_phy; - phy.is_phy_connected = gen_is_phy_connected; - phy.get_link_speed = et1011c_get_link_speed; - phy.auto_negotiate = gen_auto_negotiate; + sprintf(phy[i].name, "ET1011C @ 0x%02x", + active_phy_addr[i]); + phy[i].init = gen_init_phy; + phy[i].is_phy_connected = gen_is_phy_connected; + phy[i].get_link_speed = et1011c_get_link_speed; + phy[i].auto_negotiate = gen_auto_negotiate; break; default: - sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr); - phy.init = gen_init_phy; - phy.is_phy_connected = gen_is_phy_connected; - phy.get_link_speed = gen_get_link_speed; - phy.auto_negotiate = gen_auto_negotiate; - } + sprintf(phy[i].name, "GENERIC @ 0x%02x", + active_phy_addr[i]); + phy[i].init = gen_init_phy; + phy[i].is_phy_connected = gen_is_phy_connected; + phy[i].get_link_speed = gen_get_link_speed; + phy[i].auto_negotiate = gen_auto_negotiate; + } - debug("Ethernet PHY: %s\n", phy.name); + debug("Ethernet PHY: %s\n", phy.name); - miiphy_register(phy.name, davinci_mii_phy_read, davinci_mii_phy_write); + miiphy_register(phy[i].name, davinci_mii_phy_read, + davinci_mii_phy_write); + } return(1); } diff --git a/drivers/net/mvgbe.c b/drivers/net/mvgbe.c index c701f43..c7f7446 100644 --- a/drivers/net/mvgbe.c +++ b/drivers/net/mvgbe.c @@ -32,8 +32,10 @@ #include <net.h> #include <malloc.h> #include <miiphy.h> +#include <asm/io.h> #include <asm/errno.h> #include <asm/types.h> +#include <asm/system.h> #include <asm/byteorder.h> #if defined(CONFIG_KIRKWOOD) diff --git a/drivers/rtc/mc13783-rtc.c b/drivers/rtc/mc13783-rtc.c index 4e18f80..70ea8a1 100644 --- a/drivers/rtc/mc13783-rtc.c +++ b/drivers/rtc/mc13783-rtc.c @@ -23,24 +23,27 @@ #include <common.h> #include <rtc.h> #include <spi.h> +#include <pmic.h> #include <fsl_pmic.h> int rtc_get(struct rtc_time *rtc) { u32 day1, day2, time; int tim, i = 0; + struct pmic *p = get_pmic(); + int ret; do { - day1 = pmic_reg_read(REG_RTC_DAY); - if (day1 < 0) + ret = pmic_reg_read(p, REG_RTC_DAY, &day1); + if (ret < 0) return -1; - time = pmic_reg_read(REG_RTC_TIME); - if (time < 0) + ret = pmic_reg_read(p, REG_RTC_TIME, &time); + if (ret < 0) return -1; - day2 = pmic_reg_read(REG_RTC_DAY); - if (day2 < 0) + ret = pmic_reg_read(p, REG_RTC_DAY, &day2); + if (ret < 0) return -1; } while (day1 != day2 && i++ < 3); @@ -58,14 +61,15 @@ int rtc_get(struct rtc_time *rtc) int rtc_set(struct rtc_time *rtc) { u32 time, day; + struct pmic *p = get_pmic(); time = mktime(rtc->tm_year, rtc->tm_mon, rtc->tm_mday, rtc->tm_hour, rtc->tm_min, rtc->tm_sec); day = time / 86400; time %= 86400; - pmic_reg_write(REG_RTC_DAY, day); - pmic_reg_write(REG_RTC_TIME, time); + pmic_reg_write(p, REG_RTC_DAY, day); + pmic_reg_write(p, REG_RTC_TIME, time); return 0; } diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 056c25d..0c23955 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -37,7 +37,8 @@ void NS16550_init(NS16550_t com_port, int baud_divisor) { serial_out(CONFIG_SYS_NS16550_IER, &com_port->ier); -#if defined(CONFIG_OMAP) && !defined(CONFIG_OMAP3_ZOOM2) +#if (defined(CONFIG_OMAP) && !defined(CONFIG_OMAP3_ZOOM2)) || \ + defined(CONFIG_AM33XX) serial_out(0x7, &com_port->mdr1); /* mode select reset TL16C750*/ #endif serial_out(UART_LCR_BKSE | UART_LCRVAL, (ulong)&com_port->lcr); @@ -50,7 +51,9 @@ void NS16550_init(NS16550_t com_port, int baud_divisor) serial_out(baud_divisor & 0xff, &com_port->dll); serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm); serial_out(UART_LCRVAL, &com_port->lcr); -#if defined(CONFIG_OMAP) && !defined(CONFIG_OMAP3_ZOOM2) +#if (defined(CONFIG_OMAP) && !defined(CONFIG_OMAP3_ZOOM2)) || \ + defined(CONFIG_AM33XX) + #if defined(CONFIG_APTIX) /* /13 mode so Aptix 6MHz can hit 115200 */ serial_out(3, &com_port->mdr1); diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index 0d56e78..0d6ad62 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -28,15 +28,6 @@ #ifdef CONFIG_NS87308 #include <ns87308.h> #endif -#ifdef CONFIG_KIRKWOOD -#include <asm/arch/kirkwood.h> -#elif defined(CONFIG_ORION5X) -#include <asm/arch/orion5x.h> -#elif defined(CONFIG_ARMADA100) -#include <asm/arch/armada100.h> -#elif defined(CONFIG_PANTHEON) -#include <asm/arch/pantheon.h> -#endif #if defined (CONFIG_SERIAL_MULTI) #include <serial.h> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 96c9642..84ad6fa 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -27,6 +27,7 @@ LIB := $(obj)libspi.o COBJS-$(CONFIG_ALTERA_SPI) += altera_spi.o COBJS-$(CONFIG_ANDES_SPI) += andes_spi.o +COBJS-$(CONFIG_ARMADA100_SPI) += armada100_spi.o COBJS-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o COBJS-$(CONFIG_BFIN_SPI) += bfin_spi.o diff --git a/drivers/spi/armada100_spi.c b/drivers/spi/armada100_spi.c new file mode 100644 index 0000000..7384c9c --- /dev/null +++ b/drivers/spi/armada100_spi.c @@ -0,0 +1,228 @@ +/* + * (C) Copyright 2011 + * eInfochips Ltd. <www.einfochips.com> + * Written-by: Ajay Bhargav <ajay.bhargav@einfochips.com> + * + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Based on SSP driver + * Written-by: Lei Wen <leiwen@marvell.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + + +#include <common.h> +#include <malloc.h> +#include <spi.h> + +#include <asm/io.h> +#include <asm/arch/spi.h> +#include <asm/gpio.h> + +#define to_armd_spi_slave(s) container_of(s, struct armd_spi_slave, slave) + +struct armd_spi_slave { + struct spi_slave slave; + struct ssp_reg *spi_reg; + u32 cr0, cr1; + u32 int_cr1; + u32 clear_sr; + const void *tx; + void *rx; + int gpio_cs_inverted; +}; + +static int spi_armd_write(struct armd_spi_slave *pss) +{ + int wait_timeout = SSP_FLUSH_NUM; + while (--wait_timeout && !(readl(&pss->spi_reg->sssr) & SSSR_TNF)) + ; + if (!wait_timeout) { + debug("%s: timeout error\n", __func__); + return -1; + } + + if (pss->tx != NULL) { + writel(*(u8 *)pss->tx, &pss->spi_reg->ssdr); + ++pss->tx; + } else { + writel(0, &pss->spi_reg->ssdr); + } + return 0; +} + +static int spi_armd_read(struct armd_spi_slave *pss) +{ + int wait_timeout = SSP_FLUSH_NUM; + while (--wait_timeout && !(readl(&pss->spi_reg->sssr) & SSSR_RNE)) + ; + if (!wait_timeout) { + debug("%s: timeout error\n", __func__); + return -1; + } + + if (pss->rx != NULL) { + *(u8 *)pss->rx = readl(&pss->spi_reg->ssdr); + ++pss->rx; + } else { + readl(&pss->spi_reg->ssdr); + } + return 0; +} + +static int spi_armd_flush(struct armd_spi_slave *pss) +{ + unsigned long limit = SSP_FLUSH_NUM; + + do { + while (readl(&pss->spi_reg->sssr) & SSSR_RNE) + readl(&pss->spi_reg->ssdr); + } while ((readl(&pss->spi_reg->sssr) & SSSR_BSY) && limit--); + + writel(SSSR_ROR, &pss->spi_reg->sssr); + + return limit; +} + +void spi_cs_activate(struct spi_slave *slave) +{ + struct armd_spi_slave *pss = to_armd_spi_slave(slave); + + gpio_set_value(slave->cs, pss->gpio_cs_inverted); +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + struct armd_spi_slave *pss = to_armd_spi_slave(slave); + + gpio_set_value(slave->cs, !pss->gpio_cs_inverted); +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct armd_spi_slave *pss; + + pss = malloc(sizeof(*pss)); + if (!pss) + return NULL; + + pss->slave.bus = bus; + pss->slave.cs = cs; + pss->spi_reg = (struct ssp_reg *)SSP_REG_BASE(CONFIG_SYS_SSP_PORT); + + pss->cr0 = SSCR0_MOTO | SSCR0_DATASIZE(DEFAULT_WORD_LEN) | SSCR0_SSE; + + pss->cr1 = (SSCR1_RXTRESH(RX_THRESH_DEF) & SSCR1_RFT) | + (SSCR1_TXTRESH(TX_THRESH_DEF) & SSCR1_TFT); + pss->cr1 &= ~(SSCR1_SPO | SSCR1_SPH); + pss->cr1 |= (((mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0) + | (((mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0); + + pss->int_cr1 = SSCR1_TIE | SSCR1_RIE | SSCR1_TINTE; + pss->clear_sr = SSSR_ROR | SSSR_TINT; + + pss->gpio_cs_inverted = mode & SPI_CS_HIGH; + gpio_set_value(cs, !pss->gpio_cs_inverted); + + return &pss->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct armd_spi_slave *pss = to_armd_spi_slave(slave); + + free(pss); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct armd_spi_slave *pss = to_armd_spi_slave(slave); + + debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs); + if (spi_armd_flush(pss) == 0) + return -1; + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, + void *din, unsigned long flags) +{ + struct armd_spi_slave *pss = to_armd_spi_slave(slave); + uint bytes = bitlen / 8; + unsigned long limit; + int ret = 0; + + if (bitlen == 0) + goto done; + + /* we can only do 8 bit transfers */ + if (bitlen % 8) { + flags |= SPI_XFER_END; + goto done; + } + + if (dout) + pss->tx = dout; + else + pss->tx = NULL; + + if (din) + pss->rx = din; + else + pss->rx = NULL; + + if (flags & SPI_XFER_BEGIN) { + spi_cs_activate(slave); + writel(pss->cr1 | pss->int_cr1, &pss->spi_reg->sscr1); + writel(TIMEOUT_DEF, &pss->spi_reg->ssto); + writel(pss->cr0, &pss->spi_reg->sscr0); + } + + while (bytes--) { + limit = SSP_FLUSH_NUM; + ret = spi_armd_write(pss); + if (ret) + break; + + while ((readl(&pss->spi_reg->sssr) & SSSR_BSY) && limit--) + udelay(1); + + ret = spi_armd_read(pss); + if (ret) + break; + } + + done: + if (flags & SPI_XFER_END) { + /* Stop SSP */ + writel(pss->clear_sr, &pss->spi_reg->sssr); + clrbits_le32(&pss->spi_reg->sscr1, pss->int_cr1); + writel(0, &pss->spi_reg->ssto); + spi_cs_deactivate(slave); + } + + return ret; +} diff --git a/drivers/spi/kirkwood_spi.c b/drivers/spi/kirkwood_spi.c index 135895f..dfe542d 100644 --- a/drivers/spi/kirkwood_spi.c +++ b/drivers/spi/kirkwood_spi.c @@ -27,6 +27,7 @@ #include <common.h> #include <malloc.h> #include <spi.h> +#include <asm/io.h> #include <asm/arch/kirkwood.h> #include <asm/arch/spi.h> #include <asm/arch/mpp.h> @@ -106,6 +107,10 @@ int spi_cs_is_valid(unsigned int bus, unsigned int cs) } #endif +void spi_init(void) +{ +} + void spi_cs_activate(struct spi_slave *slave) { writel(readl(&spireg->ctrl) | KWSPI_IRQUNMASK, &spireg->ctrl); diff --git a/drivers/usb/host/ehci-kirkwood.c b/drivers/usb/host/ehci-kirkwood.c index 5570fc6..6300587 100644 --- a/drivers/usb/host/ehci-kirkwood.c +++ b/drivers/usb/host/ehci-kirkwood.c @@ -27,6 +27,7 @@ #include <usb.h> #include "ehci.h" #include "ehci-core.h" +#include <asm/arch/cpu.h> #include <asm/arch/kirkwood.h> #define rdl(off) readl(KW_USB20_BASE + (off)) |