[U-Boot] [patch V3] [1/3] PNX8181 SOC support
Jürgen Schöw
juergen at Schoew.net
Sun Jan 4 22:54:29 CET 2009
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 at 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 at emlix.com>
+ *
+ * (C) Copyright 2008, DSPG Technologies GmbH, Germany
+ * (C) Copyright 2007, NXP Semiconductors Germany GmbH
+ * Matthias Wenzel, <nxp at 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 at 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;
+}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 197 bytes
Desc: not available
Url : http://lists.denx.de/pipermail/u-boot/attachments/20090104/4453c58e/attachment.pgp
More information about the U-Boot
mailing list