
cpu/arm926ejs/pnx8181/Makefile | 45 +++ cpu/arm926ejs/pnx8181/timer.c | 141 ++++++++ drivers/i2c/Makefile | 1 + drivers/i2c/pnx8181_i2c.c | 304 +++++++++++++++++
diff --git a/cpu/arm926ejs/pnx8181/Makefile b/cpu/arm926ejs/pnx8181/Makefile new file mode 100644 index 0000000..b34d9e8 --- /dev/null +++ b/cpu/arm926ejs/pnx8181/Makefile @@ -0,0 +1,45 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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 $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).a + +COBJS = timer.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/cpu/arm926ejs/pnx8181/timer.c b/cpu/arm926ejs/pnx8181/timer.c new file mode 100644 index 0000000..585aede --- /dev/null +++ b/cpu/arm926ejs/pnx8181/timer.c @@ -0,0 +1,141 @@ +/* + * pnx8181 SOC timer routines + * + * (C) Copyright 2007-2009, emlix GmbH, Germany + * Juergen Schoew js@emlix.com + * + * (C) Copyright 2008, DSPG Technologies GmbH, Germany + * (C) Copyright 2007, NXP Semiconductors Germany GmbH + * Matthias Wenzel, nxp@mazzoo.de + * + * 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 <asm/io.h> + +/* + * timer without interrupts + */ +/* timer */ +#define PNX8181_SCTU1_BASE 0xC2102000 +#define PNX8181_SCTU2_BASE 0xC2103000 + +#define PNX8181_SCTU_TIMxCR 0x00 +#define PNX8181_SCTU_TIMxRR 0x04 +#define PNX8181_SCTU_TIMxWR 0x08 +#define PNX8181_SCTU_TIMxC0 0x0c +#define PNX8181_SCTU_TIMxC1 0x10 +#define PNX8181_SCTU_TIMxC2 0x14 +#define PNX8181_SCTU_TIMxC3 0x18 +#define PNX8181_SCTU_TIMxSR 0x1c +#define PNX8181_SCTU_TIMxPR 0x20 + +/* + * U-Boot expects a 32 bit timer, running at CONFIG_SYS_HZ + * Keep total timer count to avoid losing decrements < div_timer + */ + +/* U-Boot ticks since startup */ +static ulong timestamp; +static ulong last_timer_read; + +/* + * starts up a counter + */ +void timer_init(void) +{ + /* set prescaler to have timer run at 64 kHz */ + writeb(0x00, (void *)(PNX8181_SCTU1_BASE + PNX8181_SCTU_TIMxPR)); + + /* timer reload value = 0xffff - 13824, overflow @ 1kHz */ + writew(0xca00, (void *)(PNX8181_SCTU1_BASE + PNX8181_SCTU_TIMxRR)); + + /* timer has no interrupt, run */ + writew(0x0001, (void *)(PNX8181_SCTU1_BASE + PNX8181_SCTU_TIMxCR)); + + /* init the timestamp */ + reset_timer_masked(); +} + +ulong get_timer(ulong base_ticks) +{ + return get_timer_masked() - base_ticks; +} + +/* + * converts the timer reading to U-Boot ticks + * the timestamp is the number of ticks since reset + */ +ulong get_timer_masked(void) +{ + /* get current count */ + ulong now = readw((void *)(PNX8181_SCTU1_BASE + PNX8181_SCTU_TIMxWR)); + + if (now < last_timer_read) + timestamp += 13824; + last_timer_read = now; + + /* + * FIXME this value is empirical! + * for some reason the calculated values are way to fast + */ + return (timestamp + now) / 64; +} + +/* + * timer without interrupts + */ +void reset_timer(void) +{ + reset_timer_masked(); +} + + +/* busy-loop spin-delay */ +void sdelay(unsigned long usec) +{ + ulong i, tmp; + tmp = 42; + for (i = 0 ; i < usec*3 ; i++) + /* avoid compiler optimisation */ + tmp = -tmp; +} + +/* delay usec useconds */ +void udelay(unsigned long usec) +{ + ulong tmo, tmp; + + /* Convert to U-Boot ticks */ + tmo = usec / 1500; + + tmp = get_timer_masked(); /* get current timestamp */ + tmo += tmp; /* form target timestamp */ + + /* loop till event */ + while (get_timer_masked() < tmo) + ; +} + +void reset_timer_masked(void) +{ + /* start "advancing" time stamp from 0 */ + timestamp = 0L; +} diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 6079c05..ef457a5 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -31,6 +31,7 @@ COBJS-$(CONFIG_DRIVER_OMAP1510_I2C) += omap1510_i2c.o COBJS-$(CONFIG_DRIVER_OMAP24XX_I2C) += omap24xx_i2c.o COBJS-$(CONFIG_SOFT_I2C) += soft_i2c.o COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o +COBJS-$(CONFIG_PNX8181_I2C) += pnx8181_i2c.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/i2c/pnx8181_i2c.c b/drivers/i2c/pnx8181_i2c.c new file mode 100644 index 0000000..75a76a4 --- /dev/null +++ b/drivers/i2c/pnx8181_i2c.c @@ -0,0 +1,304 @@ +/* + * (C) Copyright 2008-2009, emlix GmbH, Germany + * Juergen Schoew js@emlix.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 <config.h> +#include <common.h> +#include <asm/io.h> + +#define I2C_TIMEOUT 10000 +#define I2C_DELAY 10 + +#define ARM_VPB1_BASE_ADDR 0xC2000000 +#define ARM_VPB3_BASE_ADDR 0xC2200000 +#define ARM_VPB_SIZE_SHIFT 12 + +#define SCON_BASE_ADDR (ARM_VPB3_BASE_ADDR + (4<<ARM_VPB_SIZE_SHIFT)) +#define SCON_BASE SCON_BASE_ADDR +#define SCON_SYSMUX1_OFFSET (0x010) +#define SCON_SYSMUX1_REG (void *)(SCON_BASE + SCON_SYSMUX1_OFFSET) +#define SCON_GPIOA27_MUX_SHIFT 22 +#define SCON_GPIOA27_MUX_FIELD (0xFFFFFFFF-(3<<SCON_GPIOA27_MUX_SHIFT)) +#define SCON_GPIOA27_SCL (1<<SCON_GPIOA27_MUX_SHIFT) +#define SCON_GPIOA28_MUX_SHIFT 24 +#define SCON_GPIOA28_MUX_FIELD (0xFFFFFFFF-(3<<SCON_GPIOA28_MUX_SHIFT)) +#define SCON_GPIOA28_SDA (1<<SCON_GPIOA28_MUX_SHIFT) + +#define CGU_BASE_ADDR (ARM_VPB3_BASE_ADDR + (0<<ARM_VPB_SIZE_SHIFT)) +#define CGU_BASE (CGU_BASE_ADDR) +#define CGU_GATESC_OFFSET (0x008) +#define CGU_GATESC_REG (void *)(CGU_BASE + CGU_GATESC_OFFSET) +#define CGU_I2C1EN 0x00000020 +#define CGU_I2CEN CGU_I2C1EN + +#define I2C_BASE_ADDR (ARM_VPB1_BASE_ADDR + (1<<ARM_VPB_SIZE_SHIFT)) +#define I2C_BASE I2C_BASE_ADDR +#define I2C_CLKHI_OFFSET (0x00C) +#define I2C_CLKHI_REG (void *)(I2C_BASE + I2C_CLKHI_OFFSET) +#define I2C_CLKLO_OFFSET (0x010) +#define I2C_CLKLO_REG (void *)(I2C_BASE + I2C_CLKLO_OFFSET) +#define I2C_ADR_OFFSET (0x014) +#define I2C_ADR_REG (void *)(I2C_BASE + I2C_ADR_OFFSET) +#define I2C_SADDR_FIELD 0xFFFFFF80 +#define I2C_HOLDDAT_OFFSET (0x018) +#define I2C_HOLDDAT_REG (void *)(I2C_BASE + I2C_HOLDDAT_OFFSET) +#define I2C_CLKDIV_FIELD 0xFFFFFC00 +#define I2C_STS_OFFSET (0x004) +#define I2C_STS_REG (void *)(I2C_BASE + I2C_STS_OFFSET) +#define I2C_CTL_OFFSET (0x008) +#define I2C_CTL_REG (void *)(I2C_BASE + I2C_CTL_OFFSET) +#define I2C_TX_OFFSET (0x000) +#define I2C_TX_REG (void *)(I2C_BASE + I2C_TX_OFFSET) +#define I2C_RX_OFFSET (0x000) +#define I2C_RX_REG (void *)(I2C_BASE + I2C_RX_OFFSET) + +#define I2C_TDI 0x00000001 +#define I2C_AFI 0x00000002 +#define I2C_NAI 0x00000004 +#define I2C_DRMI 0x00000008 +#define I2C_DRSI 0x00000010 +#define I2C_ACTIVE 0x00000020 +#define I2C_SCL 0x00000040 +#define I2C_SDA 0x00000080 +#define I2C_RFF 0x00000100 +#define I2C_RFE 0x00000200 +#define I2C_TFF 0x00000400 +#define I2C_TFE 0x00000800 +#define I2C_TFFS 0x00001000 +#define I2C_TFES 0x00002000 +#define I2C_MAST 0x00004000 + +#define I2C_RESET 0x00000100 + +#define SEND_I2C_DEVICE_ADDRESS_START_STOP(addr) \ + writel(((0x80 + addr) << 1) + 0x200, I2C_TX_REG); +#define SEND_I2C_START_ADDRESS(addr) writel((0x80 + addr) << 1, I2C_TX_REG); +#define SEND_I2C_STOP_DATA(data) writel(0x200 + data, I2C_TX_REG); +#define SEND_I2C_READ_ADDRESS(addr) \ + writel(((0x80 + addr) << 1) + 1, I2C_TX_REG); +#define SOFT_I2C_RESET \ + writel(readl(I2C_CTL_REG) | I2C_RESET, I2C_CTL_REG); + +int eeprom_write_enable(unsigned dev_addr, int state) +{ + /* nothing to be done here */ + return 0; +} + +void i2c_init(int speed, int slaveaddr) +{ + unsigned long timeout; + + writel(readl(SCON_SYSMUX1_REG) & SCON_GPIOA27_MUX_FIELD & + SCON_GPIOA28_MUX_FIELD, SCON_SYSMUX1_REG); + writel(readl(SCON_SYSMUX1_REG) | SCON_GPIOA27_SCL | SCON_GPIOA28_SDA, + SCON_SYSMUX1_REG); + writel(readl(CGU_GATESC_REG) | CGU_I2CEN, CGU_GATESC_REG); + if (speed == 400000) { + /* + * here the registers are set in order to have a 400KHz clk + * for a pclk1 of 104Mhz + */ + writel(I2C_CLKDIV_FIELD | 84, I2C_CLKHI_REG); + writel(I2C_CLKDIV_FIELD | 168, I2C_CLKLO_REG); + writel(42, I2C_HOLDDAT_REG); + } else { + speed = 100000; + /* + * here the registers are set in order to have a 100KHz clk + * for a pclk1 of 104Mhz + */ + writel(I2C_CLKDIV_FIELD | 488, I2C_CLKHI_REG); + writel(I2C_CLKDIV_FIELD | 544, I2C_CLKLO_REG); + writel(68, I2C_HOLDDAT_REG); + } + writel(slaveaddr & ~I2C_SADDR_FIELD, I2C_ADR_REG); + SOFT_I2C_RESET; + timeout = 0; + while ((readl(I2C_STS_REG) & I2C_ACTIVE) == I2C_ACTIVE) { + if (timeout > I2C_TIMEOUT) + break; + timeout++; + udelay(I2C_DELAY); + } + debug("%s: speed: %d\n", __func__, speed); +} + + +int i2c_probe(uchar chip) +{ + unsigned long timeout; + + SEND_I2C_DEVICE_ADDRESS_START_STOP(chip); + timeout = 0; + while ((readl(I2C_STS_REG) & I2C_TDI) != I2C_TDI) { + if (timeout > I2C_TIMEOUT) + return -1; + timeout++; + udelay(I2C_DELAY); + } + writel(readl(I2C_STS_REG) | I2C_TDI, I2C_STS_REG); + if ((readl(I2C_STS_REG) & I2C_NAI) == I2C_NAI) + return -1; + return 0; +} + +static int i2c_read_byte(u8 chip, u16 addr, u8 *byte) +{ + unsigned long timeout; + + timeout = 0; + while ((readl(I2C_STS_REG) & I2C_ACTIVE) == I2C_ACTIVE) { + if (timeout > I2C_TIMEOUT) + return -1; + timeout++; + udelay(I2C_DELAY); + } + SEND_I2C_START_ADDRESS(chip); + /* loop if scl=1, active=0 or drmi=0 */ + timeout = 0; + while (((readl(I2C_STS_REG) & I2C_SCL) == I2C_SCL) || + ((readl(I2C_STS_REG) & I2C_ACTIVE) != I2C_ACTIVE) || + ((readl(I2C_STS_REG) & I2C_DRMI) != I2C_DRMI)) + if (timeout > I2C_TIMEOUT) { + return -1; + timeout++; + udelay(I2C_DELAY); + } + writel((addr & 0xFF00) >> 8, I2C_TX_REG); /* ADDRESS_MODE16 */ + writel((addr & 0x00FF) >> 0, I2C_TX_REG); + SEND_I2C_READ_ADDRESS(chip); /* Dev Sel to Read */ + SEND_I2C_STOP_DATA(0x00); /* dummy write */ + timeout = 0; + while (((readl(I2C_STS_REG) & I2C_NAI) == I2C_NAI) || + ((readl(I2C_STS_REG) & I2C_TDI) != I2C_TDI) || + ((readl(I2C_STS_REG) & I2C_SCL) != I2C_SCL) || + ((readl(I2C_STS_REG) & I2C_ACTIVE) == I2C_ACTIVE) || + ((readl(I2C_STS_REG) & I2C_DRMI) == I2C_DRMI)) + if (timeout > I2C_TIMEOUT) { + return -1; + timeout++; + udelay(I2C_DELAY); + } + writel(readl(I2C_STS_REG) | I2C_TDI, I2C_STS_REG); + timeout = 0; + while ((readl(I2C_STS_REG) & I2C_TDI) == I2C_TDI) { + if (timeout > I2C_TIMEOUT) + return -1; + timeout++; + udelay(I2C_DELAY); + } + *byte = readl(I2C_RX_REG) & 0xff; + return 0; +} + +static int i2c_write_byte(u8 chip, u16 addr, u8 *byte) +{ + u8 dummy; + unsigned long timeout; + + /* wait until data is written and eeprom back again */ + timeout = 0; + dummy = 1; + while ((timeout < I2C_TIMEOUT) && (dummy != 0)) { + dummy = -i2c_probe(chip); + timeout++; + udelay(I2C_DELAY); + } + timeout = 0; + while ((readl(I2C_STS_REG) & I2C_ACTIVE) == I2C_ACTIVE) { + if (timeout > I2C_TIMEOUT) + return -1; + timeout++; + udelay(I2C_DELAY); + } + SEND_I2C_START_ADDRESS(chip); + /* loop if scl=1, active=0 or drmi=0 */ + timeout = 0; + while (((readl(I2C_STS_REG) & I2C_SCL) == I2C_SCL) || + ((readl(I2C_STS_REG) & I2C_ACTIVE) != I2C_ACTIVE) || + ((readl(I2C_STS_REG) & I2C_DRMI) != I2C_DRMI)) { + if (timeout > I2C_TIMEOUT) + return -2; + timeout++; + udelay(I2C_DELAY); + } + writel((addr & 0xFF00) >> 8, I2C_TX_REG); /* ADDRESS_MODE16 */ + writel((addr & 0x00FF) >> 0, I2C_TX_REG); + SEND_I2C_STOP_DATA(*byte); + timeout = 0; + while (((readl(I2C_STS_REG) & I2C_NAI) == I2C_NAI) || + ((readl(I2C_STS_REG) & I2C_TDI) != I2C_TDI) || + ((readl(I2C_STS_REG) & I2C_SCL) != I2C_SCL) || + ((readl(I2C_STS_REG) & I2C_ACTIVE) == I2C_ACTIVE) || + ((readl(I2C_STS_REG) & I2C_DRMI) == I2C_DRMI)) { + if (timeout > I2C_TIMEOUT) + return -3; + timeout++; + udelay(I2C_DELAY); + } + writel(readl(I2C_STS_REG) | I2C_TDI, I2C_STS_REG); + timeout = 0; + while ((readl(I2C_STS_REG) & I2C_TDI) == I2C_TDI) { + if (timeout > I2C_TIMEOUT) + return -4; + timeout++; + udelay(I2C_DELAY); + } + dummy = readl(I2C_RX_REG) & 0xff; + return 0; +} + +int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) +{ + int ret; + u8 byte; + + debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n", + __func__, chip, addr, alen, len); + while (len--) { + ret = i2c_read_byte(chip, addr, &byte); + if (ret < 0) + return -1; + *buf++ = byte; + addr++; + } + return 0; +} + +int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len) +{ + int ret; + + debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n", + __func__, chip, addr, alen, len); + while (len--) { + ret = i2c_write_byte(chip, addr++, buf++); + if (ret) { + printf("i2c_write failed chip: 0x%x addr: " + "0x%04x error %d\n", chip, addr, ret); + return -1; + } + } + return 0; +}