Merge branch 'master' of git://git.denx.de/u-boot-arm

* 'master' of git://git.denx.de/u-boot-arm: (146 commits)
  arm: Use common .lds file where possible
  arm: add a common .lds link script
  arm: Remove unneeded setting of LDCSRIPT
  Define CPUDIR for the .lds link script
  arm: Remove zipitz2 link script
  Allow arch directory to contain .lds without requiring Makefile
  OMAP: Remove omap1610inn-based boards
  arch/arm/cpu/armv7/omap-common/clocks-common.c: Fix build warnings
  board/ti/beagle/beagle.c: Fix build warnings
  sdrc.c: Fix typo in do_sdrc_init() for SPL
  tegra: i2c: Add I2C driver
  tegra: fdt: i2c: Add extra I2C bindings for U-Boot
  tegra: i2c: Select I2C ordering for Seaboard
  tegra: i2c: Enable I2C on Seaboard
  tegra: i2c: Select number of controllers for Tegra2 boards
  tegra: i2c: Initialise I2C on Nvidia boards
  tegra: Enhance clock support to handle 16-bit clock divisors
  fdt: Add function to allow aliases to refer to multiple nodes
  tegra: Rename NV_PA_PMC_BASE to TEGRA2_PMC_BASE
  tegra: fdt: Enable FDT support for Ventana
  tegra: fdt: Enable FDT support for Seaboard
  tegra: usb: Enable USB on Seaboard
  tegra: usb: Add common USB defines for tegra2 boards
  tegra: usb: Add USB support to nvidia boards
  arm: Check for valid FDT after console is up
  fdt: Avoid early panic() when there is no FDT present
  tegra: usb: Add support for Tegra USB peripheral
  tegra: fdt: Add function to return peripheral/clock ID
  usb: Add support for txfifo threshold
  tegra: usb: fdt: Add USB definitions for Tegra2 Seaboard
  tegra: usb: fdt: Add additional device tree definitions for USB ports
  tegra: fdt: Add clock bindings for Tegra2 Seaboard
  tegra: fdt: Add clock bindings
  tegra: fdt: Add additional USB binding
  fdt: Add tegra-usb bindings file from linux
  fdt: Add staging area for device tree binding documentation
  tegra: fdt: Add device tree file for Tegra2 Seaboard from kernel
  tegra: fdt: Add Tegra2x device tree file from kernel
  arm: fdt: Add skeleton device tree file from kernel
  fdt: Add basic support for decoding GPIO definitions
  fdt: Add functions to access phandles, arrays and bools
  fdt: Tidy up a few fdtdec problems
  fdt: Add tests for fdtdec
  fdt: Add fdtdec_find_aliases() to deal with alias nodes
  arm: Tegra2: Fix ELDK42 gcc failure with inline asm stack pointer load
  net: fec_mxc: allow use with cache enabled
  net: force PKTALIGN to ARCH_DMA_MINALIGN
  i.MX28: Enable caches by default
  i.MX28: Make use of the bounce buffer
  i.MX28: Do data transfers via DMA in MMC driver
  MMC: Implement generic bounce buffer
  i.MX28: Add cache support to MXS NAND driver
  i.MX28: Add cache support into the APBH DMA driver
  ARM926EJS: Implement cache operations
  board/vpac270/onenand.c: Fix build errors
  nhk8815: fix build errors
  atmel-boards: add missing atmel_mci.h
  ARM: highbank: setup env from boot source register
  ARM: highbank: change env config to use nvram
  ARM: highbank: add reset support
  ARM: highbank: Add boot counter support
  ARM: highbank: change TEXT_BASE to 0x8000
  ARM: highbank: fix us_to_tick calculation
  ARM: highbank: add missing get_tbclk
  ARM: highbank: fix warning for calxedaxgmac_initialize
  net: calxedaxgmac: fix build due to missing __aligned definition
  EXYNOS: Add structure for Exynos4 DMC
  EXYNOS: SMDK5250: Support all 4 UARTs
  ARM: fix s3c2410 timer code
  ARM: davinci: fixes for cam_enc_4xx board
  omap3_spi: receive transmit mode
  calimain, enbw_cmc: Fix typo in comments
  Davinci: ea20: use gpio framework to access gpios
  OMAP3: mt_ventoux: sets its own mtdparts
  OMAP3: mt_ventoux: updated timing for FPGA
  twl4030: fix potential power supply handling issues
  NAND: TI: fix warnings in omap_gpmc.c
  cam_enc_4xx: Rename 'images' to 'imgs'
  arm: Add Prep subcommand support to bootm
  OMAP3: twister: add support to boot Linux from SPL
  SPL: call cleanup_before_linux() before booting Linux
  OMAP3: SPL: do not call I2C init if no I2C is set.
  Add cache functions to SPL for armv7
  devkit8000: Implement and activate direct OS boot
  omap/spl: change output of spl_parse_image_header
  omap-common/spl: Add linux boot to SPL
  devkit8000/spl: init GPMC for dm9000 in SPL
  omap-common: Add NAND SPL linux booting
  devkit8000: add config for spl command
  Add cmd_spl command
  mx53ard: Initialize return code with error
  mx53: Make PLL2 to be the parent of UART clock
  configs: imx: Use CONFIG_SF_DEFAULT_CS
  mx28evk: Provide default values for SPI bus and chip select
  USB: ehci-mx6: Add proper IO accessors
  mx6: Read silicon revision from register
  i.MX28: Drop __naked function from spl_mem_init
  mxs_spi: Return proper timeout error
  i.MX28: Make the stabilization delays shorter
  pmic_i2c: Return error in case of invalid pmic_i2c_tx_num
  mx6: Remove duplicate definition of ANATOP_BASE_ADDR
  mx6: Fix reset cause for Power On Reset case
  i.MX6: mx6qsabrelite: add MACH_TYPE_MX6Q_SABRELITE
  i.MX6: mx6q_sabrelite: add CONFIG_REVISION_TAG
  i.MX28: Enable additional DRAM address bits
  mx6q: mx6qsabrelite: setup_spi() should be called in board_init to allow use for environment
  mx31: add "ARM11P power gating" to get_reset_cause
  mx31pdk: Fix CONFIG_SYS_MEMTEST_END
  efikamx: Fix CONFIG_SYS_MEMTEST_END
  mx53smd: Fix CONFIG_SYS_MEMTEST_END
  mx53evk: Fix CONFIG_SYS_MEMTEST_END
  mx51evk: Fix CONFIG_SYS_MEMTEST_END
  i.MX6: mx6qsabrelite: add ext2 support
  imximage: Remove overwriting of flash_offset
  IXP: Fix GPIO_INT_ACT_LOW_SET()
  IXP: Fix NAND build warning on PDNB3 and SCPU
  IXP: Move PDNB3 and SCPU from Makefile to boards.cfg
  IXP: Squash warnings in IXP NPE
  IXP: Fix missing MACH_TYPE_{ACTUX?,PNB3,DVLHOST}
  IXP: Make IXP buildable with arm-linux- toolchains
  Examples: Properly append LDFLAGS to LD command
  SPL: Enable YMODEM support on BeagleBone and AM335x EVM
  SPL: Add YMODEM over UART load support
  SPL: Add README.omap3
  README: document more SPL config options
  spl.c: Use __noreturn decorator
  config.mk: Check for -fstack-usage support
  config.mk: Make cc-option create a file under include/generated
  ...
This commit is contained in:
Wolfgang Denk
2012-03-30 18:09:08 +02:00
198 changed files with 6115 additions and 4194 deletions

View File

@@ -93,6 +93,21 @@ static int mxs_dma_read_semaphore(int channel)
return tmp;
}
#ifndef CONFIG_SYS_DCACHE_OFF
void mxs_dma_flush_desc(struct mxs_dma_desc *desc)
{
uint32_t addr;
uint32_t size;
addr = (uint32_t)desc;
size = roundup(sizeof(struct mxs_dma_desc), MXS_DMA_ALIGNMENT);
flush_dcache_range(addr, addr + size);
}
#else
inline void mxs_dma_flush_desc(struct mxs_dma_desc *desc) {}
#endif
/*
* Enable a DMA channel.
*
@@ -329,8 +344,10 @@ static int mxs_dma_release(int channel)
struct mxs_dma_desc *mxs_dma_desc_alloc(void)
{
struct mxs_dma_desc *pdesc;
uint32_t size;
pdesc = memalign(MXS_DMA_ALIGNMENT, sizeof(struct mxs_dma_desc));
size = roundup(sizeof(struct mxs_dma_desc), MXS_DMA_ALIGNMENT);
pdesc = memalign(MXS_DMA_ALIGNMENT, size);
if (pdesc == NULL)
return NULL;
@@ -415,12 +432,16 @@ int mxs_dma_desc_append(int channel, struct mxs_dma_desc *pdesc)
last->cmd.next = mxs_dma_cmd_address(pdesc);
last->cmd.data |= MXS_DMA_DESC_CHAIN;
mxs_dma_flush_desc(last);
}
pdesc->flags |= MXS_DMA_DESC_READY;
if (pdesc->flags & MXS_DMA_DESC_FIRST)
pchan->pending_num++;
list_add_tail(&pdesc->node, &pchan->active);
mxs_dma_flush_desc(pdesc);
return ret;
}

View File

@@ -73,8 +73,8 @@ int gpio_get_value(unsigned gpio)
{
uint32_t bank = PAD_BANK(gpio);
uint32_t offset = PINCTRL_DIN(bank);
struct mx28_register *reg =
(struct mx28_register *)(MXS_PINCTRL_BASE + offset);
struct mx28_register_32 *reg =
(struct mx28_register_32 *)(MXS_PINCTRL_BASE + offset);
return (readl(&reg->reg) >> PAD_PIN(gpio)) & 1;
}
@@ -83,8 +83,8 @@ void gpio_set_value(unsigned gpio, int value)
{
uint32_t bank = PAD_BANK(gpio);
uint32_t offset = PINCTRL_DOUT(bank);
struct mx28_register *reg =
(struct mx28_register *)(MXS_PINCTRL_BASE + offset);
struct mx28_register_32 *reg =
(struct mx28_register_32 *)(MXS_PINCTRL_BASE + offset);
if (value)
writel(1 << PAD_PIN(gpio), &reg->reg_set);
@@ -96,8 +96,8 @@ int gpio_direction_input(unsigned gpio)
{
uint32_t bank = PAD_BANK(gpio);
uint32_t offset = PINCTRL_DOE(bank);
struct mx28_register *reg =
(struct mx28_register *)(MXS_PINCTRL_BASE + offset);
struct mx28_register_32 *reg =
(struct mx28_register_32 *)(MXS_PINCTRL_BASE + offset);
writel(1 << PAD_PIN(gpio), &reg->reg_clr);
@@ -108,8 +108,8 @@ int gpio_direction_output(unsigned gpio, int value)
{
uint32_t bank = PAD_BANK(gpio);
uint32_t offset = PINCTRL_DOE(bank);
struct mx28_register *reg =
(struct mx28_register *)(MXS_PINCTRL_BASE + offset);
struct mx28_register_32 *reg =
(struct mx28_register_32 *)(MXS_PINCTRL_BASE + offset);
writel(1 << PAD_PIN(gpio), &reg->reg_set);

View File

@@ -41,6 +41,7 @@ COBJS-$(CONFIG_DRIVER_S3C24X0_I2C) += s3c24x0_i2c.o
COBJS-$(CONFIG_S3C44B0_I2C) += s3c44b0_i2c.o
COBJS-$(CONFIG_SOFT_I2C) += soft_i2c.o
COBJS-$(CONFIG_SPEAR_I2C) += spr_i2c.o
COBJS-$(CONFIG_TEGRA_I2C) += tegra_i2c.o
COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o
COBJS-$(CONFIG_U8500_I2C) += u8500_i2c.o
COBJS-$(CONFIG_SH_I2C) += sh_i2c.o

569
drivers/i2c/tegra_i2c.c Normal file
View File

@@ -0,0 +1,569 @@
/*
* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
* Copyright (c) 2010-2011 NVIDIA Corporation
* NVIDIA Corporation <www.nvidia.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 <fdtdec.h>
#include <i2c.h>
#include <asm/io.h>
#include <asm/arch/clk_rst.h>
#include <asm/arch/clock.h>
#include <asm/arch/funcmux.h>
#include <asm/arch/gpio.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/tegra_i2c.h>
DECLARE_GLOBAL_DATA_PTR;
static unsigned int i2c_bus_num;
/* Information about i2c controller */
struct i2c_bus {
int id;
enum periph_id periph_id;
int speed;
int pinmux_config;
struct i2c_control *control;
struct i2c_ctlr *regs;
int is_dvc; /* DVC type, rather than I2C */
int inited; /* bus is inited */
};
static struct i2c_bus i2c_controllers[TEGRA_I2C_NUM_CONTROLLERS];
static void set_packet_mode(struct i2c_bus *i2c_bus)
{
u32 config;
config = I2C_CNFG_NEW_MASTER_FSM_MASK | I2C_CNFG_PACKET_MODE_MASK;
if (i2c_bus->is_dvc) {
struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
writel(config, &dvc->cnfg);
} else {
writel(config, &i2c_bus->regs->cnfg);
/*
* program I2C_SL_CNFG.NEWSL to ENABLE. This fixes probe
* issues, i.e., some slaves may be wrongly detected.
*/
setbits_le32(&i2c_bus->regs->sl_cnfg, I2C_SL_CNFG_NEWSL_MASK);
}
}
static void i2c_reset_controller(struct i2c_bus *i2c_bus)
{
/* Reset I2C controller. */
reset_periph(i2c_bus->periph_id, 1);
/* re-program config register to packet mode */
set_packet_mode(i2c_bus);
}
static void i2c_init_controller(struct i2c_bus *i2c_bus)
{
/*
* Use PLLP - DP-04508-001_v06 datasheet indicates a divisor of 8
* here, in section 23.3.1, but in fact we seem to need a factor of
* 16 to get the right frequency.
*/
clock_start_periph_pll(i2c_bus->periph_id, CLOCK_ID_PERIPH,
i2c_bus->speed * 2 * 8);
/* Reset I2C controller. */
i2c_reset_controller(i2c_bus);
/* Configure I2C controller. */
if (i2c_bus->is_dvc) { /* only for DVC I2C */
struct dvc_ctlr *dvc = (struct dvc_ctlr *)i2c_bus->regs;
setbits_le32(&dvc->ctrl3, DVC_CTRL_REG3_I2C_HW_SW_PROG_MASK);
}
funcmux_select(i2c_bus->periph_id, i2c_bus->pinmux_config);
}
static void send_packet_headers(
struct i2c_bus *i2c_bus,
struct i2c_trans_info *trans,
u32 packet_id)
{
u32 data;
/* prepare header1: Header size = 0 Protocol = I2C, pktType = 0 */
data = PROTOCOL_TYPE_I2C << PKT_HDR1_PROTOCOL_SHIFT;
data |= packet_id << PKT_HDR1_PKT_ID_SHIFT;
data |= i2c_bus->id << PKT_HDR1_CTLR_ID_SHIFT;
writel(data, &i2c_bus->control->tx_fifo);
debug("pkt header 1 sent (0x%x)\n", data);
/* prepare header2 */
data = (trans->num_bytes - 1) << PKT_HDR2_PAYLOAD_SIZE_SHIFT;
writel(data, &i2c_bus->control->tx_fifo);
debug("pkt header 2 sent (0x%x)\n", data);
/* prepare IO specific header: configure the slave address */
data = trans->address << PKT_HDR3_SLAVE_ADDR_SHIFT;
/* Enable Read if it is not a write transaction */
if (!(trans->flags & I2C_IS_WRITE))
data |= PKT_HDR3_READ_MODE_MASK;
/* Write I2C specific header */
writel(data, &i2c_bus->control->tx_fifo);
debug("pkt header 3 sent (0x%x)\n", data);
}
static int wait_for_tx_fifo_empty(struct i2c_control *control)
{
u32 count;
int timeout_us = I2C_TIMEOUT_USEC;
while (timeout_us >= 0) {
count = (readl(&control->fifo_status) & TX_FIFO_EMPTY_CNT_MASK)
>> TX_FIFO_EMPTY_CNT_SHIFT;
if (count == I2C_FIFO_DEPTH)
return 1;
udelay(10);
timeout_us -= 10;
}
return 0;
}
static int wait_for_rx_fifo_notempty(struct i2c_control *control)
{
u32 count;
int timeout_us = I2C_TIMEOUT_USEC;
while (timeout_us >= 0) {
count = (readl(&control->fifo_status) & TX_FIFO_FULL_CNT_MASK)
>> TX_FIFO_FULL_CNT_SHIFT;
if (count)
return 1;
udelay(10);
timeout_us -= 10;
}
return 0;
}
static int wait_for_transfer_complete(struct i2c_control *control)
{
int int_status;
int timeout_us = I2C_TIMEOUT_USEC;
while (timeout_us >= 0) {
int_status = readl(&control->int_status);
if (int_status & I2C_INT_NO_ACK_MASK)
return -int_status;
if (int_status & I2C_INT_ARBITRATION_LOST_MASK)
return -int_status;
if (int_status & I2C_INT_XFER_COMPLETE_MASK)
return 0;
udelay(10);
timeout_us -= 10;
}
return -1;
}
static int send_recv_packets(struct i2c_bus *i2c_bus,
struct i2c_trans_info *trans)
{
struct i2c_control *control = i2c_bus->control;
u32 int_status;
u32 words;
u8 *dptr;
u32 local;
uchar last_bytes;
int error = 0;
int is_write = trans->flags & I2C_IS_WRITE;
/* clear status from previous transaction, XFER_COMPLETE, NOACK, etc. */
int_status = readl(&control->int_status);
writel(int_status, &control->int_status);
send_packet_headers(i2c_bus, trans, 1);
words = DIV_ROUND_UP(trans->num_bytes, 4);
last_bytes = trans->num_bytes & 3;
dptr = trans->buf;
while (words) {
u32 *wptr = (u32 *)dptr;
if (is_write) {
/* deal with word alignment */
if ((unsigned)dptr & 3) {
memcpy(&local, dptr, sizeof(u32));
writel(local, &control->tx_fifo);
debug("pkt data sent (0x%x)\n", local);
} else {
writel(*wptr, &control->tx_fifo);
debug("pkt data sent (0x%x)\n", *wptr);
}
if (!wait_for_tx_fifo_empty(control)) {
error = -1;
goto exit;
}
} else {
if (!wait_for_rx_fifo_notempty(control)) {
error = -1;
goto exit;
}
/*
* for the last word, we read into our local buffer,
* in case that caller did not provide enough buffer.
*/
local = readl(&control->rx_fifo);
if ((words == 1) && last_bytes)
memcpy(dptr, (char *)&local, last_bytes);
else if ((unsigned)dptr & 3)
memcpy(dptr, &local, sizeof(u32));
else
*wptr = local;
debug("pkt data received (0x%x)\n", local);
}
words--;
dptr += sizeof(u32);
}
if (wait_for_transfer_complete(control)) {
error = -1;
goto exit;
}
return 0;
exit:
/* error, reset the controller. */
i2c_reset_controller(i2c_bus);
return error;
}
static int tegra2_i2c_write_data(u32 addr, u8 *data, u32 len)
{
int error;
struct i2c_trans_info trans_info;
trans_info.address = addr;
trans_info.buf = data;
trans_info.flags = I2C_IS_WRITE;
trans_info.num_bytes = len;
trans_info.is_10bit_address = 0;
error = send_recv_packets(&i2c_controllers[i2c_bus_num], &trans_info);
if (error)
debug("tegra2_i2c_write_data: Error (%d) !!!\n", error);
return error;
}
static int tegra2_i2c_read_data(u32 addr, u8 *data, u32 len)
{
int error;
struct i2c_trans_info trans_info;
trans_info.address = addr | 1;
trans_info.buf = data;
trans_info.flags = 0;
trans_info.num_bytes = len;
trans_info.is_10bit_address = 0;
error = send_recv_packets(&i2c_controllers[i2c_bus_num], &trans_info);
if (error)
debug("tegra2_i2c_read_data: Error (%d) !!!\n", error);
return error;
}
#ifndef CONFIG_OF_CONTROL
#error "Please enable device tree support to use this driver"
#endif
unsigned int i2c_get_bus_speed(void)
{
return i2c_controllers[i2c_bus_num].speed;
}
int i2c_set_bus_speed(unsigned int speed)
{
struct i2c_bus *i2c_bus;
i2c_bus = &i2c_controllers[i2c_bus_num];
i2c_bus->speed = speed;
i2c_init_controller(i2c_bus);
return 0;
}
static int i2c_get_config(const void *blob, int node, struct i2c_bus *i2c_bus)
{
i2c_bus->regs = (struct i2c_ctlr *)fdtdec_get_addr(blob, node, "reg");
/*
* We don't have a binding for pinmux yet. Leave it out for now. So
* far no one needs anything other than the default.
*/
i2c_bus->pinmux_config = FUNCMUX_DEFAULT;
i2c_bus->speed = fdtdec_get_int(blob, node, "clock-frequency", 0);
i2c_bus->periph_id = clock_decode_periph_id(blob, node);
/*
* We can't specify the pinmux config in the fdt, so I2C2 will not
* work on Seaboard. It normally has no devices on it anyway.
* You could add in this little hack if you need to use it.
* The correct solution is a pinmux binding in the fdt.
*
* if (i2c_bus->periph_id == PERIPH_ID_I2C2)
* i2c_bus->pinmux_config = FUNCMUX_I2C2_PTA;
*/
if (i2c_bus->periph_id == -1)
return -FDT_ERR_NOTFOUND;
return 0;
}
/*
* Process a list of nodes, adding them to our list of I2C ports.
*
* @param blob fdt blob
* @param node_list list of nodes to process (any <=0 are ignored)
* @param count number of nodes to process
* @param is_dvc 1 if these are DVC ports, 0 if standard I2C
* @return 0 if ok, -1 on error
*/
static int process_nodes(const void *blob, int node_list[], int count,
int is_dvc)
{
struct i2c_bus *i2c_bus;
int i;
/* build the i2c_controllers[] for each controller */
for (i = 0; i < count; i++) {
int node = node_list[i];
if (node <= 0)
continue;
i2c_bus = &i2c_controllers[i];
i2c_bus->id = i;
if (i2c_get_config(blob, node, i2c_bus)) {
printf("i2c_init_board: failed to decode bus %d\n", i);
return -1;
}
i2c_bus->is_dvc = is_dvc;
if (is_dvc) {
i2c_bus->control =
&((struct dvc_ctlr *)i2c_bus->regs)->control;
} else {
i2c_bus->control = &i2c_bus->regs->control;
}
debug("%s: controller bus %d at %p, periph_id %d, speed %d: ",
is_dvc ? "dvc" : "i2c", i, i2c_bus->regs,
i2c_bus->periph_id, i2c_bus->speed);
i2c_init_controller(i2c_bus);
debug("ok\n");
i2c_bus->inited = 1;
/* Mark position as used */
node_list[i] = -1;
}
return 0;
}
/* Sadly there is no error return from this function */
void i2c_init_board(void)
{
int node_list[TEGRA_I2C_NUM_CONTROLLERS];
const void *blob = gd->fdt_blob;
int count;
/* First get the normal i2c ports */
count = fdtdec_find_aliases_for_id(blob, "i2c",
COMPAT_NVIDIA_TEGRA20_I2C, node_list,
TEGRA_I2C_NUM_CONTROLLERS);
if (process_nodes(blob, node_list, count, 0))
return;
/* Now look for dvc ports */
count = fdtdec_add_aliases_for_id(blob, "i2c",
COMPAT_NVIDIA_TEGRA20_DVC, node_list,
TEGRA_I2C_NUM_CONTROLLERS);
if (process_nodes(blob, node_list, count, 1))
return;
}
void i2c_init(int speed, int slaveaddr)
{
/* This will override the speed selected in the fdt for that port */
debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
i2c_set_bus_speed(speed);
}
/* i2c write version without the register address */
int i2c_write_data(uchar chip, uchar *buffer, int len)
{
int rc;
debug("i2c_write_data: chip=0x%x, len=0x%x\n", chip, len);
debug("write_data: ");
/* use rc for counter */
for (rc = 0; rc < len; ++rc)
debug(" 0x%02x", buffer[rc]);
debug("\n");
/* Shift 7-bit address over for lower-level i2c functions */
rc = tegra2_i2c_write_data(chip << 1, buffer, len);
if (rc)
debug("i2c_write_data(): rc=%d\n", rc);
return rc;
}
/* i2c read version without the register address */
int i2c_read_data(uchar chip, uchar *buffer, int len)
{
int rc;
debug("inside i2c_read_data():\n");
/* Shift 7-bit address over for lower-level i2c functions */
rc = tegra2_i2c_read_data(chip << 1, buffer, len);
if (rc) {
debug("i2c_read_data(): rc=%d\n", rc);
return rc;
}
debug("i2c_read_data: ");
/* reuse rc for counter*/
for (rc = 0; rc < len; ++rc)
debug(" 0x%02x", buffer[rc]);
debug("\n");
return 0;
}
/* Probe to see if a chip is present. */
int i2c_probe(uchar chip)
{
int rc;
uchar reg;
debug("i2c_probe: addr=0x%x\n", chip);
reg = 0;
rc = i2c_write_data(chip, &reg, 1);
if (rc) {
debug("Error probing 0x%x.\n", chip);
return 1;
}
return 0;
}
static int i2c_addr_ok(const uint addr, const int alen)
{
/* We support 7 or 10 bit addresses, so one or two bytes each */
return alen == 1 || alen == 2;
}
/* Read bytes */
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
uint offset;
int i;
debug("i2c_read: chip=0x%x, addr=0x%x, len=0x%x\n",
chip, addr, len);
if (!i2c_addr_ok(addr, alen)) {
debug("i2c_read: Bad address %x.%d.\n", addr, alen);
return 1;
}
for (offset = 0; offset < len; offset++) {
if (alen) {
uchar data[alen];
for (i = 0; i < alen; i++) {
data[alen - i - 1] =
(addr + offset) >> (8 * i);
}
if (i2c_write_data(chip, data, alen)) {
debug("i2c_read: error sending (0x%x)\n",
addr);
return 1;
}
}
if (i2c_read_data(chip, buffer + offset, 1)) {
debug("i2c_read: error reading (0x%x)\n", addr);
return 1;
}
}
return 0;
}
/* Write bytes */
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
uint offset;
int i;
debug("i2c_write: chip=0x%x, addr=0x%x, len=0x%x\n",
chip, addr, len);
if (!i2c_addr_ok(addr, alen)) {
debug("i2c_write: Bad address %x.%d.\n", addr, alen);
return 1;
}
for (offset = 0; offset < len; offset++) {
uchar data[alen + 1];
for (i = 0; i < alen; i++)
data[alen - i - 1] = (addr + offset) >> (8 * i);
data[alen] = buffer[offset];
if (i2c_write_data(chip, data, alen + 1)) {
debug("i2c_write: error sending (0x%x)\n", addr);
return 1;
}
}
return 0;
}
#if defined(CONFIG_I2C_MULTI_BUS)
/*
* Functions for multiple I2C bus handling
*/
unsigned int i2c_get_bus_num(void)
{
return i2c_bus_num;
}
int i2c_set_bus_num(unsigned int bus)
{
if (bus >= TEGRA_I2C_NUM_CONTROLLERS || !i2c_controllers[bus].inited)
return -1;
i2c_bus_num = bus;
return 0;
}
#endif

View File

@@ -47,6 +47,9 @@ int pmic_reg_write(struct pmic *p, u32 reg, u32 val)
case 1:
buf[0] = val & 0xff;
break;
default:
printf("%s: invalid tx_num: %d", __func__, pmic_i2c_tx_num);
return -1;
}
if (i2c_write(pmic_i2c_addr, reg, 1, buf, pmic_i2c_tx_num))
@@ -73,6 +76,9 @@ int pmic_reg_read(struct pmic *p, u32 reg, u32 *val)
case 1:
ret_val = buf[0];
break;
default:
printf("%s: invalid tx_num: %d", __func__, pmic_i2c_tx_num);
return -1;
}
memcpy(val, &ret_val, sizeof(ret_val));

View File

@@ -47,10 +47,105 @@ int __board_mmc_getcd(struct mmc *mmc) {
int board_mmc_getcd(struct mmc *mmc)__attribute__((weak,
alias("__board_mmc_getcd")));
#ifdef CONFIG_MMC_BOUNCE_BUFFER
static int mmc_bounce_need_bounce(struct mmc_data *orig)
{
ulong addr, len;
if (orig->flags & MMC_DATA_READ)
addr = (ulong)orig->dest;
else
addr = (ulong)orig->src;
if (addr % ARCH_DMA_MINALIGN) {
debug("MMC: Unaligned data destination address %08lx!\n", addr);
return 1;
}
len = (ulong)(orig->blocksize * orig->blocks);
if (len % ARCH_DMA_MINALIGN) {
debug("MMC: Unaligned data destination length %08lx!\n", len);
return 1;
}
return 0;
}
static int mmc_bounce_buffer_start(struct mmc_data *backup,
struct mmc_data *orig)
{
ulong origlen, len;
void *buffer;
if (!orig)
return 0;
if (!mmc_bounce_need_bounce(orig))
return 0;
memcpy(backup, orig, sizeof(struct mmc_data));
origlen = orig->blocksize * orig->blocks;
len = roundup(origlen, ARCH_DMA_MINALIGN);
buffer = memalign(ARCH_DMA_MINALIGN, len);
if (!buffer) {
puts("MMC: Error allocating MMC bounce buffer!\n");
return 1;
}
if (orig->flags & MMC_DATA_READ) {
orig->dest = buffer;
} else {
memcpy(buffer, orig->src, origlen);
orig->src = buffer;
}
return 0;
}
static void mmc_bounce_buffer_stop(struct mmc_data *backup,
struct mmc_data *orig)
{
ulong len;
if (!orig)
return;
if (!mmc_bounce_need_bounce(backup))
return;
if (backup->flags & MMC_DATA_READ) {
len = backup->blocksize * backup->blocks;
memcpy(backup->dest, orig->dest, len);
free(orig->dest);
orig->dest = backup->dest;
} else {
free((void *)orig->src);
orig->src = backup->src;
}
return;
}
#else
static inline int mmc_bounce_buffer_start(struct mmc_data *backup,
struct mmc_data *orig) { }
static inline void mmc_bounce_buffer_stop(struct mmc_data *backup,
struct mmc_data *orig) { }
#endif
int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
{
#ifdef CONFIG_MMC_TRACE
struct mmc_data backup;
int ret;
memset(&backup, 0, sizeof(backup));
ret = mmc_bounce_buffer_start(&backup, data);
if (ret)
return ret;
#ifdef CONFIG_MMC_TRACE
int i;
u8 *ptr;
@@ -99,10 +194,11 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
printf("\t\tERROR MMC rsp not supported\n");
break;
}
return ret;
#else
return mmc->send_cmd(mmc, cmd, data);
ret = mmc->send_cmd(mmc, cmd, data);
#endif
mmc_bounce_buffer_stop(&backup, data);
return ret;
}
int mmc_send_status(struct mmc *mmc, int timeout)

View File

@@ -41,6 +41,7 @@
#include <asm/arch/clock.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/dma.h>
struct mxsmmc_priv {
int id;
@@ -49,6 +50,7 @@ struct mxsmmc_priv {
uint32_t *clkctrl_ssp;
uint32_t buswidth;
int (*mmc_is_wp)(int);
struct mxs_dma_desc *desc;
};
#define MXSMMC_MAX_TIMEOUT 10000
@@ -64,8 +66,7 @@ mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
struct mx28_ssp_regs *ssp_regs = priv->regs;
uint32_t reg;
int timeout;
uint32_t data_count;
uint32_t *data_ptr;
uint32_t data_count, cache_data_count;
uint32_t ctrl0;
debug("MMC%d: CMD%d\n", mmc->block_dev.dev, cmd->cmdidx);
@@ -183,40 +184,41 @@ mxsmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
if (!data)
return 0;
/* Process the data */
data_count = data->blocksize * data->blocks;
timeout = MXSMMC_MAX_TIMEOUT;
if (data_count % ARCH_DMA_MINALIGN)
cache_data_count = roundup(data_count, ARCH_DMA_MINALIGN);
else
cache_data_count = data_count;
if (data->flags & MMC_DATA_READ) {
data_ptr = (uint32_t *)data->dest;
while (data_count && --timeout) {
reg = readl(&ssp_regs->hw_ssp_status);
if (!(reg & SSP_STATUS_FIFO_EMPTY)) {
*data_ptr++ = readl(&ssp_regs->hw_ssp_data);
data_count -= 4;
timeout = MXSMMC_MAX_TIMEOUT;
} else
udelay(1000);
}
priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_WRITE;
priv->desc->cmd.address = (dma_addr_t)data->dest;
} else {
data_ptr = (uint32_t *)data->src;
timeout *= 100;
while (data_count && --timeout) {
reg = readl(&ssp_regs->hw_ssp_status);
if (!(reg & SSP_STATUS_FIFO_FULL)) {
writel(*data_ptr++, &ssp_regs->hw_ssp_data);
data_count -= 4;
timeout = MXSMMC_MAX_TIMEOUT;
} else
udelay(1000);
}
priv->desc->cmd.data = MXS_DMA_DESC_COMMAND_DMA_READ;
priv->desc->cmd.address = (dma_addr_t)data->src;
/* Flush data to DRAM so DMA can pick them up */
flush_dcache_range((uint32_t)priv->desc->cmd.address,
(uint32_t)(priv->desc->cmd.address + cache_data_count));
}
if (!timeout) {
printf("MMC%d: Data timeout with command %d (status 0x%08x)!\n",
mmc->block_dev.dev, cmd->cmdidx, reg);
priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM |
(data_count << MXS_DMA_DESC_BYTES_OFFSET);
mxs_dma_desc_append(MXS_DMA_CHANNEL_AHB_APBH_SSP0, priv->desc);
if (mxs_dma_go(MXS_DMA_CHANNEL_AHB_APBH_SSP0)) {
printf("MMC%d: DMA transfer failed\n", mmc->block_dev.dev);
return COMM_ERR;
}
/* The data arrived into DRAM, invalidate cache over them */
if (data->flags & MMC_DATA_READ) {
invalidate_dcache_range((uint32_t)priv->desc->cmd.address,
(uint32_t)(priv->desc->cmd.address + cache_data_count));
}
/* Check data errors */
reg = readl(&ssp_regs->hw_ssp_status);
if (reg &
@@ -270,7 +272,8 @@ static int mxsmmc_init(struct mmc *mmc)
/* 8 bits word length in MMC mode */
clrsetbits_le32(&ssp_regs->hw_ssp_ctrl1,
SSP_CTRL1_SSP_MODE_MASK | SSP_CTRL1_WORD_LENGTH_MASK,
SSP_CTRL1_SSP_MODE_SD_MMC | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS);
SSP_CTRL1_SSP_MODE_SD_MMC | SSP_CTRL1_WORD_LENGTH_EIGHT_BITS |
SSP_CTRL1_DMA_ENABLE);
/* Set initial bit clock 400 KHz */
mx28_set_ssp_busclock(priv->id, 400);
@@ -300,6 +303,13 @@ int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int))
return -ENOMEM;
}
priv->desc = mxs_dma_desc_alloc();
if (!priv->desc) {
free(priv);
free(mmc);
return -ENOMEM;
}
priv->mmc_is_wp = wp;
priv->id = id;
switch (id) {
@@ -345,7 +355,7 @@ int mxsmmc_initialize(bd_t *bis, int id, int (*wp)(int))
*/
mmc->f_min = 400000;
mmc->f_max = mxc_get_clock(MXC_SSP0_CLK + id) * 1000 / 2;
mmc->b_max = 0;
mmc->b_max = 0x40;
mmc_register(mmc);
return 0;

View File

@@ -50,6 +50,7 @@ struct mxs_nand_info {
int cur_chip;
uint32_t cmd_queue_len;
uint32_t data_buf_size;
uint8_t *cmd_buf;
uint8_t *data_buf;
@@ -73,6 +74,36 @@ struct mxs_nand_info {
struct nand_ecclayout fake_ecc_layout;
/*
* Cache management functions
*/
#ifndef CONFIG_SYS_DCACHE_OFF
static void mxs_nand_flush_data_buf(struct mxs_nand_info *info)
{
uint32_t addr = (uint32_t)info->data_buf;
flush_dcache_range(addr, addr + info->data_buf_size);
}
static void mxs_nand_inval_data_buf(struct mxs_nand_info *info)
{
uint32_t addr = (uint32_t)info->data_buf;
invalidate_dcache_range(addr, addr + info->data_buf_size);
}
static void mxs_nand_flush_cmd_buf(struct mxs_nand_info *info)
{
uint32_t addr = (uint32_t)info->cmd_buf;
flush_dcache_range(addr, addr + MXS_NAND_COMMAND_BUFFER_SIZE);
}
#else
static inline void mxs_nand_flush_data_buf(struct mxs_nand_info *info) {}
static inline void mxs_nand_inval_data_buf(struct mxs_nand_info *info) {}
static inline void mxs_nand_flush_cmd_buf(struct mxs_nand_info *info) {}
#endif
static struct mxs_dma_desc *mxs_nand_get_dma_desc(struct mxs_nand_info *info)
{
struct mxs_dma_desc *desc;
@@ -286,6 +317,9 @@ static void mxs_nand_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
mxs_dma_desc_append(channel, d);
/* Flush caches */
mxs_nand_flush_cmd_buf(nand_info);
/* Execute the DMA chain. */
ret = mxs_dma_go(channel);
if (ret)
@@ -435,6 +469,9 @@ static void mxs_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int length)
goto rtn;
}
/* Invalidate caches */
mxs_nand_inval_data_buf(nand_info);
memcpy(buf, nand_info->data_buf, length);
rtn:
@@ -484,6 +521,9 @@ static void mxs_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
mxs_dma_desc_append(channel, d);
/* Flush caches */
mxs_nand_flush_data_buf(nand_info);
/* Execute the DMA chain. */
ret = mxs_dma_go(channel);
if (ret)
@@ -600,6 +640,9 @@ static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand,
goto rtn;
}
/* Invalidate caches */
mxs_nand_inval_data_buf(nand_info);
/* Read DMA completed, now do the mark swapping. */
mxs_nand_swap_block_mark(mtd, nand_info->data_buf, nand_info->oob_buf);
@@ -687,6 +730,9 @@ static void mxs_nand_ecc_write_page(struct mtd_info *mtd,
mxs_dma_desc_append(channel, d);
/* Flush caches */
mxs_nand_flush_data_buf(nand_info);
/* Execute the DMA chain. */
ret = mxs_dma_go(channel);
if (ret) {
@@ -978,18 +1024,19 @@ int mxs_nand_alloc_buffers(struct mxs_nand_info *nand_info)
uint8_t *buf;
const int size = NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE;
nand_info->data_buf_size = roundup(size, MXS_DMA_ALIGNMENT);
/* DMA buffers */
buf = memalign(MXS_DMA_ALIGNMENT, size);
buf = memalign(MXS_DMA_ALIGNMENT, nand_info->data_buf_size);
if (!buf) {
printf("MXS NAND: Error allocating DMA buffers\n");
return -ENOMEM;
}
memset(buf, 0, size);
memset(buf, 0, nand_info->data_buf_size);
nand_info->data_buf = buf;
nand_info->oob_buf = buf + NAND_MAX_PAGESIZE;
/* Command buffers */
nand_info->cmd_buf = memalign(MXS_DMA_ALIGNMENT,
MXS_NAND_COMMAND_BUFFER_SIZE);

View File

@@ -27,10 +27,12 @@
#include <asm/arch/mem.h>
#include <asm/arch/omap_gpmc.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/compiler.h>
#include <nand.h>
static uint8_t cs;
static struct nand_ecclayout hw_nand_oob = GPMC_NAND_HW_ECC_LAYOUT;
static __maybe_unused struct nand_ecclayout hw_nand_oob =
GPMC_NAND_HW_ECC_LAYOUT;
/*
* omap_nand_hwcontrol - Set the address pointers corretly for the
@@ -75,7 +77,7 @@ int omap_spl_dev_ready(struct mtd_info *mtd)
* @mtd: MTD device structure
*
*/
static void omap_hwecc_init(struct nand_chip *chip)
static void __maybe_unused omap_hwecc_init(struct nand_chip *chip)
{
/*
* Init ECC Control Register
@@ -113,7 +115,7 @@ static uint32_t gen_true_ecc(uint8_t *ecc_buf)
*
* @return 0 if data is OK or corrected, else returns -1
*/
static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
uint8_t *read_ecc, uint8_t *calc_ecc)
{
uint32_t orig_ecc, new_ecc, res, hm;
@@ -179,8 +181,8 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
* @dat: unused
* @ecc_code: ecc_code buffer
*/
static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
uint8_t *ecc_code)
static int __maybe_unused omap_calculate_ecc(struct mtd_info *mtd,
const uint8_t *dat, uint8_t *ecc_code)
{
u_int32_t val;
@@ -205,7 +207,7 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
* @mtd: MTD device structure
* @mode: Read/Write mode
*/
static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
static void __maybe_unused omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
{
struct nand_chip *chip = mtd->priv;
uint32_t val, dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1;

View File

@@ -16,6 +16,7 @@
*/
#include <common.h>
#include <malloc.h>
#include <linux/compiler.h>
#include <linux/err.h>
#include <asm/io.h>

View File

@@ -38,16 +38,28 @@ DECLARE_GLOBAL_DATA_PTR;
#error "CONFIG_MII has to be defined!"
#endif
#ifndef CONFIG_FEC_XCV_TYPE
#define CONFIG_FEC_XCV_TYPE MII100
#ifndef CONFIG_FEC_XCV_TYPE
#define CONFIG_FEC_XCV_TYPE MII100
#endif
/*
* The i.MX28 operates with packets in big endian. We need to swap them before
* sending and after receiving.
*/
#ifdef CONFIG_MX28
#define CONFIG_FEC_MXC_SWAP_PACKET
#ifdef CONFIG_MX28
#define CONFIG_FEC_MXC_SWAP_PACKET
#endif
#define RXDESC_PER_CACHELINE (ARCH_DMA_MINALIGN/sizeof(struct fec_bd))
/* Check various alignment issues at compile time */
#if ((ARCH_DMA_MINALIGN < 16) || (ARCH_DMA_MINALIGN % 16 != 0))
#error "ARCH_DMA_MINALIGN must be multiple of 16!"
#endif
#if ((PKTALIGN < ARCH_DMA_MINALIGN) || \
(PKTALIGN % ARCH_DMA_MINALIGN != 0))
#error "PKTALIGN must be multiple of ARCH_DMA_MINALIGN!"
#endif
#undef DEBUG
@@ -59,7 +71,7 @@ struct nbuf {
uint8_t head[16]; /**< MAC header(6 + 6 + 2) + 2(aligned) */
};
#ifdef CONFIG_FEC_MXC_SWAP_PACKET
#ifdef CONFIG_FEC_MXC_SWAP_PACKET
static void swap_packet(uint32_t *packet, int length)
{
int i;
@@ -259,43 +271,52 @@ static int fec_tx_task_disable(struct fec_priv *fec)
* Initialize receive task's buffer descriptors
* @param[in] fec all we know about the device yet
* @param[in] count receive buffer count to be allocated
* @param[in] size size of each receive buffer
* @param[in] dsize desired size of each receive buffer
* @return 0 on success
*
* For this task we need additional memory for the data buffers. And each
* data buffer requires some alignment. Thy must be aligned to a specific
* boundary each (DB_DATA_ALIGNMENT).
* boundary each.
*/
static int fec_rbd_init(struct fec_priv *fec, int count, int size)
static int fec_rbd_init(struct fec_priv *fec, int count, int dsize)
{
int ix;
uint32_t p = 0;
uint32_t size;
int i;
/* reserve data memory and consider alignment */
if (fec->rdb_ptr == NULL)
fec->rdb_ptr = malloc(size * count + DB_DATA_ALIGNMENT);
p = (uint32_t)fec->rdb_ptr;
if (!p) {
puts("fec_mxc: not enough malloc memory\n");
return -ENOMEM;
}
memset((void *)p, 0, size * count + DB_DATA_ALIGNMENT);
p += DB_DATA_ALIGNMENT-1;
p &= ~(DB_DATA_ALIGNMENT-1);
for (ix = 0; ix < count; ix++) {
writel(p, &fec->rbd_base[ix].data_pointer);
p += size;
writew(FEC_RBD_EMPTY, &fec->rbd_base[ix].status);
writew(0, &fec->rbd_base[ix].data_length);
}
/*
* mark the last RBD to close the ring
* Allocate memory for the buffers. This allocation respects the
* alignment
*/
writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &fec->rbd_base[ix - 1].status);
size = roundup(dsize, ARCH_DMA_MINALIGN);
for (i = 0; i < count; i++) {
uint32_t data_ptr = readl(&fec->rbd_base[i].data_pointer);
if (data_ptr == 0) {
uint8_t *data = memalign(ARCH_DMA_MINALIGN,
size);
if (!data) {
printf("%s: error allocating rxbuf %d\n",
__func__, i);
goto err;
}
writel((uint32_t)data, &fec->rbd_base[i].data_pointer);
} /* needs allocation */
writew(FEC_RBD_EMPTY, &fec->rbd_base[i].status);
writew(0, &fec->rbd_base[i].data_length);
}
/* Mark the last RBD to close the ring. */
writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &fec->rbd_base[i - 1].status);
fec->rbd_index = 0;
return 0;
err:
for (; i >= 0; i--) {
uint32_t data_ptr = readl(&fec->rbd_base[i].data_pointer);
free((void *)data_ptr);
}
return -ENOMEM;
}
/**
@@ -312,9 +333,13 @@ static int fec_rbd_init(struct fec_priv *fec, int count, int size)
*/
static void fec_tbd_init(struct fec_priv *fec)
{
unsigned addr = (unsigned)fec->tbd_base;
unsigned size = roundup(2 * sizeof(struct fec_bd),
ARCH_DMA_MINALIGN);
writew(0x0000, &fec->tbd_base[0].status);
writew(FEC_TBD_WRAP, &fec->tbd_base[1].status);
fec->tbd_index = 0;
flush_dcache_range(addr, addr+size);
}
/**
@@ -324,16 +349,10 @@ static void fec_tbd_init(struct fec_priv *fec)
*/
static void fec_rbd_clean(int last, struct fec_bd *pRbd)
{
/*
* Reset buffer descriptor as empty
*/
unsigned short flags = FEC_RBD_EMPTY;
if (last)
writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &pRbd->status);
else
writew(FEC_RBD_EMPTY, &pRbd->status);
/*
* no data in it
*/
flags |= FEC_RBD_WRAP;
writew(flags, &pRbd->status);
writew(0, &pRbd->data_length);
}
@@ -387,12 +406,25 @@ static int fec_open(struct eth_device *edev)
{
struct fec_priv *fec = (struct fec_priv *)edev->priv;
int speed;
uint32_t addr, size;
int i;
debug("fec_open: fec_open(dev)\n");
/* full-duplex, heartbeat disabled */
writel(1 << 2, &fec->eth->x_cntrl);
fec->rbd_index = 0;
/* Invalidate all descriptors */
for (i = 0; i < FEC_RBD_NUM - 1; i++)
fec_rbd_clean(0, &fec->rbd_base[i]);
fec_rbd_clean(1, &fec->rbd_base[i]);
/* Flush the descriptors into RAM */
size = roundup(FEC_RBD_NUM * sizeof(struct fec_bd),
ARCH_DMA_MINALIGN);
addr = (uint32_t)fec->rbd_base;
flush_dcache_range(addr, addr + size);
#ifdef FEC_QUIRK_ENET_MAC
/* Enable ENET HW endian SWAP */
writel(readl(&fec->eth->ecntrl) | FEC_ECNTRL_DBSWAP,
@@ -478,38 +510,55 @@ static int fec_open(struct eth_device *edev)
static int fec_init(struct eth_device *dev, bd_t* bd)
{
uint32_t base;
struct fec_priv *fec = (struct fec_priv *)dev->priv;
uint32_t mib_ptr = (uint32_t)&fec->eth->rmon_t_drop;
uint32_t rcntrl;
int i;
uint32_t size;
int i, ret;
/* Initialize MAC address */
fec_set_hwaddr(dev);
/*
* reserve memory for both buffer descriptor chains at once
* Datasheet forces the startaddress of each chain is 16 byte
* aligned
* Allocate transmit descriptors, there are two in total. This
* allocation respects cache alignment.
*/
if (fec->base_ptr == NULL)
fec->base_ptr = malloc((2 + FEC_RBD_NUM) *
sizeof(struct fec_bd) + DB_ALIGNMENT);
base = (uint32_t)fec->base_ptr;
if (!base) {
puts("fec_mxc: not enough malloc memory\n");
return -ENOMEM;
if (!fec->tbd_base) {
size = roundup(2 * sizeof(struct fec_bd),
ARCH_DMA_MINALIGN);
fec->tbd_base = memalign(ARCH_DMA_MINALIGN, size);
if (!fec->tbd_base) {
ret = -ENOMEM;
goto err1;
}
memset(fec->tbd_base, 0, size);
fec_tbd_init(fec);
flush_dcache_range((unsigned)fec->tbd_base, size);
}
memset((void *)base, 0, (2 + FEC_RBD_NUM) *
sizeof(struct fec_bd) + DB_ALIGNMENT);
base += (DB_ALIGNMENT-1);
base &= ~(DB_ALIGNMENT-1);
fec->rbd_base = (struct fec_bd *)base;
base += FEC_RBD_NUM * sizeof(struct fec_bd);
fec->tbd_base = (struct fec_bd *)base;
/*
* Allocate receive descriptors. This allocation respects cache
* alignment.
*/
if (!fec->rbd_base) {
size = roundup(FEC_RBD_NUM * sizeof(struct fec_bd),
ARCH_DMA_MINALIGN);
fec->rbd_base = memalign(ARCH_DMA_MINALIGN, size);
if (!fec->rbd_base) {
ret = -ENOMEM;
goto err2;
}
memset(fec->rbd_base, 0, size);
/*
* Initialize RxBD ring
*/
if (fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE) < 0) {
ret = -ENOMEM;
goto err3;
}
flush_dcache_range((unsigned)fec->rbd_base,
(unsigned)fec->rbd_base + size);
}
/*
* Set interrupt mask register
@@ -566,23 +615,19 @@ static int fec_init(struct eth_device *dev, bd_t* bd)
writel((uint32_t)fec->tbd_base, &fec->eth->etdsr);
writel((uint32_t)fec->rbd_base, &fec->eth->erdsr);
/*
* Initialize RxBD/TxBD rings
*/
if (fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE) < 0) {
free(fec->base_ptr);
fec->base_ptr = NULL;
return -ENOMEM;
}
fec_tbd_init(fec);
#ifndef CONFIG_PHYLIB
if (fec->xcv_type != SEVENWIRE)
miiphy_restart_aneg(dev);
#endif
fec_open(dev);
return 0;
err3:
free(fec->rbd_base);
err2:
free(fec->tbd_base);
err1:
return ret;
}
/**
@@ -631,9 +676,11 @@ static void fec_halt(struct eth_device *dev)
* @param[in] length Data count in bytes
* @return 0 on success
*/
static int fec_send(struct eth_device *dev, volatile void* packet, int length)
static int fec_send(struct eth_device *dev, volatile void *packet, int length)
{
unsigned int status;
uint32_t size;
uint32_t addr;
/*
* This routine transmits one frame. This routine only accepts
@@ -650,15 +697,21 @@ static int fec_send(struct eth_device *dev, volatile void* packet, int length)
}
/*
* Setup the transmit buffer
* Note: We are always using the first buffer for transmission,
* the second will be empty and only used to stop the DMA engine
* Setup the transmit buffer. We are always using the first buffer for
* transmission, the second will be empty and only used to stop the DMA
* engine. We also flush the packet to RAM here to avoid cache trouble.
*/
#ifdef CONFIG_FEC_MXC_SWAP_PACKET
#ifdef CONFIG_FEC_MXC_SWAP_PACKET
swap_packet((uint32_t *)packet, length);
#endif
addr = (uint32_t)packet;
size = roundup(length, ARCH_DMA_MINALIGN);
flush_dcache_range(addr, addr + size);
writew(length, &fec->tbd_base[fec->tbd_index].data_length);
writel((uint32_t)packet, &fec->tbd_base[fec->tbd_index].data_pointer);
writel(addr, &fec->tbd_base[fec->tbd_index].data_pointer);
/*
* update BD's status now
* This block:
@@ -671,17 +724,31 @@ static int fec_send(struct eth_device *dev, volatile void* packet, int length)
status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
writew(status, &fec->tbd_base[fec->tbd_index].status);
/*
* Flush data cache. This code flushes both TX descriptors to RAM.
* After this code, the descriptors will be safely in RAM and we
* can start DMA.
*/
size = roundup(2 * sizeof(struct fec_bd), ARCH_DMA_MINALIGN);
addr = (uint32_t)fec->tbd_base;
flush_dcache_range(addr, addr + size);
/*
* Enable SmartDMA transmit task
*/
fec_tx_task_enable(fec);
/*
* wait until frame is sent .
* Wait until frame is sent. On each turn of the wait cycle, we must
* invalidate data cache to see what's really in RAM. Also, we need
* barrier here.
*/
invalidate_dcache_range(addr, addr + size);
while (readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_READY) {
udelay(1);
invalidate_dcache_range(addr, addr + size);
}
debug("fec_send: status 0x%x index %d\n",
readw(&fec->tbd_base[fec->tbd_index].status),
fec->tbd_index);
@@ -707,6 +774,8 @@ static int fec_recv(struct eth_device *dev)
int frame_length, len = 0;
struct nbuf *frame;
uint16_t bd_status;
uint32_t addr, size;
int i;
uchar buff[FEC_MAX_PKT_SIZE];
/*
@@ -737,8 +806,23 @@ static int fec_recv(struct eth_device *dev)
}
/*
* ensure reading the right buffer status
* Read the buffer status. Before the status can be read, the data cache
* must be invalidated, because the data in RAM might have been changed
* by DMA. The descriptors are properly aligned to cachelines so there's
* no need to worry they'd overlap.
*
* WARNING: By invalidating the descriptor here, we also invalidate
* the descriptors surrounding this one. Therefore we can NOT change the
* contents of this descriptor nor the surrounding ones. The problem is
* that in order to mark the descriptor as processed, we need to change
* the descriptor. The solution is to mark the whole cache line when all
* descriptors in the cache line are processed.
*/
addr = (uint32_t)rbd;
addr &= ~(ARCH_DMA_MINALIGN - 1);
size = roundup(sizeof(struct fec_bd), ARCH_DMA_MINALIGN);
invalidate_dcache_range(addr, addr + size);
bd_status = readw(&rbd->status);
debug("fec_recv: status 0x%x\n", bd_status);
@@ -750,10 +834,17 @@ static int fec_recv(struct eth_device *dev)
*/
frame = (struct nbuf *)readl(&rbd->data_pointer);
frame_length = readw(&rbd->data_length) - 4;
/*
* Invalidate data cache over the buffer
*/
addr = (uint32_t)frame;
size = roundup(frame_length, ARCH_DMA_MINALIGN);
invalidate_dcache_range(addr, addr + size);
/*
* Fill the buffer and pass it to upper layers
*/
#ifdef CONFIG_FEC_MXC_SWAP_PACKET
#ifdef CONFIG_FEC_MXC_SWAP_PACKET
swap_packet((uint32_t *)frame->data, frame_length);
#endif
memcpy(buff, frame->data, frame_length);
@@ -765,11 +856,25 @@ static int fec_recv(struct eth_device *dev)
(ulong)rbd->data_pointer,
bd_status);
}
/*
* free the current buffer, restart the engine
* and move forward to the next buffer
* Free the current buffer, restart the engine and move forward
* to the next buffer. Here we check if the whole cacheline of
* descriptors was already processed and if so, we mark it free
* as whole.
*/
fec_rbd_clean(fec->rbd_index == (FEC_RBD_NUM - 1) ? 1 : 0, rbd);
size = RXDESC_PER_CACHELINE - 1;
if ((fec->rbd_index & size) == size) {
i = fec->rbd_index - size;
addr = (uint32_t)&fec->rbd_base[i];
for (; i <= fec->rbd_index ; i++) {
fec_rbd_clean(i == (FEC_RBD_NUM - 1),
&fec->rbd_base[i]);
}
flush_dcache_range(addr,
addr + ARCH_DMA_MINALIGN);
}
fec_rx_task_enable(fec);
fec->rbd_index = (fec->rbd_index + 1) % FEC_RBD_NUM;
}
@@ -866,7 +971,7 @@ static int fec_probe(bd_t *bd, int dev_id, int phy_id, uint32_t base_addr)
bus->read = fec_phy_read;
bus->write = fec_phy_write;
sprintf(bus->name, edev->name);
#ifdef CONFIG_MX28
#ifdef CONFIG_MX28
/*
* The i.MX28 has two ethernet interfaces, but they are not equal.
* Only the first one can access the MDIO bus.
@@ -901,7 +1006,7 @@ err1:
return ret;
}
#ifndef CONFIG_FEC_MXC_MULTI
#ifndef CONFIG_FEC_MXC_MULTI
int fecmxc_initialize(bd_t *bd)
{
int lout = 1;

View File

@@ -233,22 +233,6 @@ struct ethernet_regs {
#define MIIGSK_ENR_EN (1 << 1)
#endif
/**
* @brief Descriptor buffer alignment
*
* i.MX27 requires a 16 byte alignment (but for the first element only)
*/
#define DB_ALIGNMENT 16
/**
* @brief Data buffer alignment
*
* i.MX27 requires a four byte alignment for transmit and 16 bits
* alignment for receive so take 16
* Note: Valid for member data_pointer in struct buffer_descriptor
*/
#define DB_DATA_ALIGNMENT 16
/**
* @brief Receive & Transmit Buffer Descriptor definitions
*
@@ -282,8 +266,7 @@ struct fec_priv {
struct fec_bd *tbd_base; /* TBD ring */
int tbd_index; /* next transmit BD to write */
bd_t *bd;
void *rdb_ptr;
void *base_ptr;
uint8_t *tdb_ptr;
int dev_id;
int phy_id;
struct mii_dev *bus;

View File

@@ -27,7 +27,6 @@ LIB := $(obj)libpcmcia.o
COBJS-$(CONFIG_I82365) += i82365.o
COBJS-$(CONFIG_8xx) += mpc8xx_pcmcia.o
COBJS-$(CONFIG_PXA_PCMCIA) += pxa_pcmcia.o
COBJS-y += rpx_pcmcia.o
COBJS-$(CONFIG_IDE_TI_CARDBUS) += ti_pci1410a.o
COBJS-y += tqm8xx_pcmcia.o

View File

@@ -1,93 +0,0 @@
#include <common.h>
#include <config.h>
#include <pcmcia.h>
#include <asm/arch/pxa-regs.h>
#include <asm/io.h>
static inline void msWait(unsigned msVal)
{
udelay(msVal*1000);
}
int pcmcia_on (void)
{
unsigned int reg_arr[] = {
0x48000028, CONFIG_SYS_MCMEM0_VAL,
0x4800002c, CONFIG_SYS_MCMEM1_VAL,
0x48000030, CONFIG_SYS_MCATT0_VAL,
0x48000034, CONFIG_SYS_MCATT1_VAL,
0x48000038, CONFIG_SYS_MCIO0_VAL,
0x4800003c, CONFIG_SYS_MCIO1_VAL,
0, 0
};
int i, rc;
#ifdef CONFIG_EXADRON1
int cardDetect;
volatile unsigned int *v_pBCRReg =
(volatile unsigned int *) 0x08000000;
#endif
debug ("%s\n", __FUNCTION__);
i = 0;
while (reg_arr[i]) {
(*(volatile unsigned int *) reg_arr[i]) |= reg_arr[i + 1];
i += 2;
}
udelay (1000);
debug ("%s: programmed mem controller \n", __FUNCTION__);
#ifdef CONFIG_EXADRON1
/*define useful BCR masks */
#define BCR_CF_INIT_VAL 0x00007230
#define BCR_CF_PWRON_BUSOFF_RESETOFF_VAL 0x00007231
#define BCR_CF_PWRON_BUSOFF_RESETON_VAL 0x00007233
#define BCR_CF_PWRON_BUSON_RESETON_VAL 0x00007213
#define BCR_CF_PWRON_BUSON_RESETOFF_VAL 0x00007211
/* we see from the GPIO bit if the card is present */
cardDetect = !(GPLR0 & GPIO_bit (14));
if (cardDetect) {
printf ("No PCMCIA card found!\n");
}
/* reset the card via the BCR line */
*v_pBCRReg = (unsigned) BCR_CF_INIT_VAL;
msWait (500);
*v_pBCRReg = (unsigned) BCR_CF_PWRON_BUSOFF_RESETOFF_VAL;
msWait (500);
*v_pBCRReg = (unsigned) BCR_CF_PWRON_BUSOFF_RESETON_VAL;
msWait (500);
*v_pBCRReg = (unsigned) BCR_CF_PWRON_BUSON_RESETON_VAL;
msWait (500);
*v_pBCRReg = (unsigned) BCR_CF_PWRON_BUSON_RESETOFF_VAL;
msWait (1500);
/* enable address bus */
GPCR1 = 0x01;
/* and the first CF slot */
MECR = 0x00000002;
#endif /* EXADRON 1 */
rc = check_ide_device (0); /* use just slot 0 */
return rc;
}
#if defined(CONFIG_CMD_PCMCIA)
int pcmcia_off (void)
{
return 0;
}
#endif

View File

@@ -65,13 +65,23 @@ void twl4030_power_reset_init(void)
void twl4030_pmrecv_vsel_cfg(u8 vsel_reg, u8 vsel_val,
u8 dev_grp, u8 dev_grp_sel)
{
/* Select the Device Group */
twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, dev_grp_sel,
dev_grp);
int ret;
/* Select the Voltage */
twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, vsel_val,
ret = twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, vsel_val,
vsel_reg);
if (ret != 0) {
printf("Could could not write vsel to reg %02x (%d)\n",
vsel_reg, ret);
return;
}
/* Select the Device Group (enable the supply if dev_grp_sel != 0) */
ret = twl4030_i2c_write_u8(TWL4030_CHIP_PM_RECEIVER, dev_grp_sel,
dev_grp);
if (ret != 0)
printf("Could could not write grp_sel to reg %02x (%d)\n",
dev_grp, ret);
}
void twl4030_power_init(void)

View File

@@ -162,7 +162,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
if (mx28_wait_mask_set(&ssp_regs->hw_ssp_ctrl0_reg,
SSP_CTRL0_RUN, MXS_SPI_MAX_TIMEOUT)) {
printf("MXS SPI: Timeout waiting for start\n");
return -1;
return -ETIMEDOUT;
}
if (tx)
@@ -174,7 +174,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
if (mx28_wait_mask_clr(&ssp_regs->hw_ssp_status_reg,
SSP_STATUS_FIFO_EMPTY, MXS_SPI_MAX_TIMEOUT)) {
printf("MXS SPI: Timeout waiting for data\n");
return -1;
return -ETIMEDOUT;
}
*rx = readl(&ssp_regs->hw_ssp_data);
@@ -184,7 +184,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
if (mx28_wait_mask_clr(&ssp_regs->hw_ssp_ctrl0_reg,
SSP_CTRL0_RUN, MXS_SPI_MAX_TIMEOUT)) {
printf("MXS SPI: Timeout waiting for finish\n");
return -1;
return -ETIMEDOUT;
}
}

View File

@@ -297,6 +297,65 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp,
return 0;
}
/*McSPI Transmit Receive Mode*/
int omap3_spi_txrx(struct spi_slave *slave,
unsigned int len, const u8 *txp, u8 *rxp, unsigned long flags)
{
struct omap3_spi_slave *ds = to_omap3_spi(slave);
int timeout = SPI_WAIT_TIMEOUT;
int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
int irqstatus = readl(&ds->regs->irqstatus);
int i=0;
/*Enable SPI channel*/
if (flags & SPI_XFER_BEGIN)
writel(OMAP3_MCSPI_CHCTRL_EN,
&ds->regs->channel[ds->slave.cs].chctrl);
/*set TRANSMIT-RECEIVE Mode*/
chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
chconf |= OMAP3_MCSPI_CHCONF_FORCE;
writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
/*Shift in and out 1 byte at time*/
for (i=0; i < len; i++){
/* Write: wait for TX empty (TXS == 1)*/
irqstatus |= (1<< (4*(ds->slave.bus)));
while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
OMAP3_MCSPI_CHSTAT_TXS)) {
if (--timeout <= 0) {
printf("SPI TXS timed out, status=0x%08x\n",
readl(&ds->regs->channel[ds->slave.cs].chstat));
return -1;
}
}
/* Write the data */
writel(txp[i], &ds->regs->channel[ds->slave.cs].tx);
/*Read: wait for RX containing data (RXS == 1)*/
while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
OMAP3_MCSPI_CHSTAT_RXS)) {
if (--timeout <= 0) {
printf("SPI RXS timed out, status=0x%08x\n",
readl(&ds->regs->channel[ds->slave.cs].chstat));
return -1;
}
}
/* Read the data */
rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx);
}
/*if transfer must be terminated disable the channel*/
if (flags & SPI_XFER_END) {
chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
writel(chconf, &ds->regs->channel[ds->slave.cs].chconf);
writel(0, &ds->regs->channel[ds->slave.cs].chctrl);
}
return 0;
}
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
const void *dout, void *din, unsigned long flags)
{
@@ -329,10 +388,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
}
ret = 0;
} else {
if (dout != NULL)
if (dout != NULL && din != NULL)
ret = omap3_spi_txrx(slave, len, txp, rxp, flags);
else if (dout != NULL)
ret = omap3_spi_write(slave, len, txp, flags);
if (din != NULL)
else if (din != NULL)
ret = omap3_spi_read(slave, len, rxp, flags);
}
return ret;

View File

@@ -109,6 +109,8 @@ static inline struct omap3_spi_slave *to_omap3_spi(struct spi_slave *slave)
return container_of(slave, struct omap3_spi_slave, slave);
}
int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, const u8 *txp,
u8 *rxp, unsigned long flags);
int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp,
unsigned long flags);
int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp,

View File

@@ -44,11 +44,13 @@ endif
COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
COBJS-$(CONFIG_USB_EHCI_MX5) += ehci-mx5.o
COBJS-$(CONFIG_USB_EHCI_MX6) += ehci-mx6.o
COBJS-$(CONFIG_USB_EHCI_OMAP) += ehci-omap.o
COBJS-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o
COBJS-$(CONFIG_USB_EHCI_IXP4XX) += ehci-ixp.o
COBJS-$(CONFIG_USB_EHCI_MARVELL) += ehci-marvell.o
COBJS-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
COBJS-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
COBJS-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
COBJS := $(COBJS-y)

View File

@@ -255,6 +255,13 @@ static int ehci_reset(void)
#endif
ehci_writel(reg_ptr, tmp);
}
#ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
cmd = ehci_readl(&hcor->or_txfilltuning);
cmd &= ~TXFIFO_THRESH(0x3f);
cmd |= TXFIFO_THRESH(CONFIG_USB_EHCI_TXFIFO_THRESH);
ehci_writel(&hcor->or_txfilltuning, cmd);
#endif
out:
return ret;
}

200
drivers/usb/host/ehci-mx6.c Normal file
View File

@@ -0,0 +1,200 @@
/*
* Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
* Copyright (C) 2010 Freescale Semiconductor, Inc.
*
* 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.
*/
#include <common.h>
#include <usb.h>
#include <errno.h>
#include <linux/compiler.h>
#include <usb/ehci-fsl.h>
#include <asm/io.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
#include <asm/arch/mx6x_pins.h>
#include <asm/arch/iomux-v3.h>
#include "ehci.h"
#include "ehci-core.h"
#define USB_OTGREGS_OFFSET 0x000
#define USB_H1REGS_OFFSET 0x200
#define USB_H2REGS_OFFSET 0x400
#define USB_H3REGS_OFFSET 0x600
#define USB_OTHERREGS_OFFSET 0x800
#define USB_H1_CTRL_OFFSET 0x04
#define USBPHY_CTRL 0x00000030
#define USBPHY_CTRL_SET 0x00000034
#define USBPHY_CTRL_CLR 0x00000038
#define USBPHY_CTRL_TOG 0x0000003c
#define USBPHY_PWD 0x00000000
#define USBPHY_CTRL_SFTRST 0x80000000
#define USBPHY_CTRL_CLKGATE 0x40000000
#define USBPHY_CTRL_ENUTMILEVEL3 0x00008000
#define USBPHY_CTRL_ENUTMILEVEL2 0x00004000
#define ANADIG_USB2_CHRG_DETECT_EN_B 0x00100000
#define ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B 0x00080000
#define ANADIG_USB2_PLL_480_CTRL_BYPASS 0x00010000
#define ANADIG_USB2_PLL_480_CTRL_ENABLE 0x00002000
#define ANADIG_USB2_PLL_480_CTRL_POWER 0x00001000
#define ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS 0x00000040
#define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */
#define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */
/* USBCMD */
#define UH1_USBCMD_OFFSET 0x140
#define UCMD_RUN_STOP (1 << 0) /* controller run/stop */
#define UCMD_RESET (1 << 1) /* controller reset */
static void usbh1_internal_phy_clock_gate(int on)
{
void __iomem *phy_reg = (void __iomem *)USB_PHY1_BASE_ADDR;
phy_reg += on ? USBPHY_CTRL_CLR : USBPHY_CTRL_SET;
__raw_writel(USBPHY_CTRL_CLKGATE, phy_reg);
}
static void usbh1_power_config(void)
{
struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
/*
* Some phy and power's special controls for host1
* 1. The external charger detector needs to be disabled
* or the signal at DP will be poor
* 2. The PLL's power and output to usb for host 1
* is totally controlled by IC, so the Software only needs
* to enable them at initializtion.
*/
__raw_writel(ANADIG_USB2_CHRG_DETECT_EN_B |
ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B,
&anatop->usb2_chrg_detect);
__raw_writel(ANADIG_USB2_PLL_480_CTRL_BYPASS,
&anatop->usb2_pll_480_ctrl);
__raw_writel(ANADIG_USB2_PLL_480_CTRL_ENABLE |
ANADIG_USB2_PLL_480_CTRL_POWER |
ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS,
&anatop->usb2_pll_480_ctrl_set);
}
static int usbh1_phy_enable(void)
{
void __iomem *phy_reg = (void __iomem *)USB_PHY1_BASE_ADDR;
void __iomem *phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL);
void __iomem *usb_cmd = (void __iomem *)(USBOH3_USB_BASE_ADDR +
USB_H1REGS_OFFSET +
UH1_USBCMD_OFFSET);
u32 val;
/* Stop then Reset */
val = __raw_readl(usb_cmd);
val &= ~UCMD_RUN_STOP;
__raw_writel(val, usb_cmd);
while (__raw_readl(usb_cmd) & UCMD_RUN_STOP)
;
val = __raw_readl(usb_cmd);
val |= UCMD_RESET;
__raw_writel(val, usb_cmd);
while (__raw_readl(usb_cmd) & UCMD_RESET)
;
/* Reset USBPHY module */
val = __raw_readl(phy_ctrl);
val |= USBPHY_CTRL_SFTRST;
__raw_writel(val, phy_ctrl);
udelay(10);
/* Remove CLKGATE and SFTRST */
val = __raw_readl(phy_ctrl);
val &= ~(USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST);
__raw_writel(val, phy_ctrl);
udelay(10);
/* Power up the PHY */
__raw_writel(0, phy_reg + USBPHY_PWD);
/* enable FS/LS device */
val = __raw_readl(phy_reg + USBPHY_CTRL);
val |= (USBPHY_CTRL_ENUTMILEVEL2 | USBPHY_CTRL_ENUTMILEVEL3);
__raw_writel(val, phy_reg + USBPHY_CTRL);
return 0;
}
static void usbh1_oc_config(void)
{
void __iomem *usb_base = (void __iomem *)USBOH3_USB_BASE_ADDR;
void __iomem *usbother_base = usb_base + USB_OTHERREGS_OFFSET;
u32 val;
val = __raw_readl(usbother_base + USB_H1_CTRL_OFFSET);
#if CONFIG_MACH_TYPE == MACH_TYPE_MX6Q_ARM2
/* mx6qarm2 seems to required a different setting*/
val &= ~UCTRL_OVER_CUR_POL;
#else
val |= UCTRL_OVER_CUR_POL;
#endif
__raw_writel(val, usbother_base + USB_H1_CTRL_OFFSET);
val = __raw_readl(usbother_base + USB_H1_CTRL_OFFSET);
val |= UCTRL_OVER_CUR_DIS;
__raw_writel(val, usbother_base + USB_H1_CTRL_OFFSET);
}
int ehci_hcd_init(void)
{
struct usb_ehci *ehci;
enable_usboh3_clk(1);
mdelay(1);
/* Do board specific initialization */
board_ehci_hcd_init(CONFIG_MXC_USB_PORT);
#if CONFIG_MXC_USB_PORT == 1
/* USB Host 1 */
usbh1_power_config();
usbh1_oc_config();
usbh1_internal_phy_clock_gate(1);
usbh1_phy_enable();
#else
#error "MXC USB port not yet supported"
#endif
ehci = (struct usb_ehci *)(USBOH3_USB_BASE_ADDR +
(0x200 * CONFIG_MXC_USB_PORT));
hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
hcor = (struct ehci_hcor *)((uint32_t)hccr +
HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
setbits_le32(&ehci->usbmode, CM_HOST);
__raw_writel(CONFIG_MXC_USB_PORTSC, &ehci->portsc);
setbits_le32(&ehci->portsc, USB_EN);
mdelay(10);
return 0;
}
int ehci_hcd_stop(void)
{
return 0;
}

View File

@@ -75,8 +75,8 @@ int ehci_hcd_init(void)
int ret;
uint32_t usb_base, cap_base;
struct mx28_register *digctl_ctrl =
(struct mx28_register *)HW_DIGCTL_CTRL;
struct mx28_register_32 *digctl_ctrl =
(struct mx28_register_32 *)HW_DIGCTL_CTRL;
struct mx28_clkctrl_regs *clkctrl_regs =
(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;
@@ -119,8 +119,8 @@ int ehci_hcd_stop(void)
{
int ret;
uint32_t tmp;
struct mx28_register *digctl_ctrl =
(struct mx28_register *)HW_DIGCTL_CTRL;
struct mx28_register_32 *digctl_ctrl =
(struct mx28_register_32 *)HW_DIGCTL_CTRL;
struct mx28_clkctrl_regs *clkctrl_regs =
(struct mx28_clkctrl_regs *)MXS_CLKCTRL_BASE;

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2009 NVIDIA Corporation
*
* 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 <usb.h>
#include "ehci.h"
#include "ehci-core.h"
#include <asm/errno.h>
#include <asm/arch/usb.h>
/*
* Create the appropriate control structures to manage
* a new EHCI host controller.
*/
int ehci_hcd_init(void)
{
u32 our_hccr, our_hcor;
/*
* Select the first port, as we don't have a way of selecting others
* yet
*/
if (tegrausb_start_port(0, &our_hccr, &our_hcor))
return -1;
hccr = (struct ehci_hccr *)our_hccr;
hcor = (struct ehci_hcor *)our_hcor;
return 0;
}
/*
* Destroy the appropriate control structures corresponding
* the the EHCI host controller.
*/
int ehci_hcd_stop(void)
{
tegrausb_stop_port();
return 0;
}

View File

@@ -80,7 +80,11 @@ struct ehci_hcor {
uint32_t or_ctrldssegment;
uint32_t or_periodiclistbase;
uint32_t or_asynclistaddr;
uint32_t _reserved_[9];
uint32_t _reserved_0_;
uint32_t or_burstsize;
uint32_t or_txfilltuning;
#define TXFIFO_THRESH(p) ((p & 0x3f) << 16)
uint32_t _reserved_1_[6];
uint32_t or_configflag;
#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */
uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS];