[coreboot] New patch to review for coreboot: 6bc9ddc snow: use bootblock build class for I2C code

David Hendricks (dhendrix@chromium.org) gerrit at coreboot.org
Wed Feb 6 00:06:58 CET 2013


David Hendricks (dhendrix at chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/2289

-gerrit

commit 6bc9ddc4ee87c1baed0c91436edb6b9ad32999f3
Author: David Hendricks <dhendrix at chromium.org>
Date:   Tue Feb 5 14:50:30 2013 -0800

    snow: use bootblock build class for I2C code
    
    This gets rid of a bunch of duplicate I2C code in the bootblock.
    
    Change-Id: I51f625a0f738cca4ed2453fbcb78092e4110bc7e
    Signed-off-by: David Hendricks <dhendrix at chromium.org>
---
 src/cpu/samsung/s5p-common/Makefile.inc |   1 +
 src/mainboard/google/snow/bootblock.c   | 402 +-------------------------------
 2 files changed, 2 insertions(+), 401 deletions(-)

diff --git a/src/cpu/samsung/s5p-common/Makefile.inc b/src/cpu/samsung/s5p-common/Makefile.inc
index 0f4200c..621576d 100644
--- a/src/cpu/samsung/s5p-common/Makefile.inc
+++ b/src/cpu/samsung/s5p-common/Makefile.inc
@@ -1,4 +1,5 @@
 bootblock-y += pwm.c
+bootblock-y += s3c24x0_i2c.c
 bootblock-y += s5p_gpio.c
 bootblock-y += timer.c
 
diff --git a/src/mainboard/google/snow/bootblock.c b/src/mainboard/google/snow/bootblock.c
index 0507fb2..1985662 100644
--- a/src/mainboard/google/snow/bootblock.c
+++ b/src/mainboard/google/snow/bootblock.c
@@ -68,76 +68,7 @@ static void do_serial(void)
 	uart_init();
 }
 
-#define I2C_WRITE	0
-#define I2C_READ	1
-
-#define I2C_OK		0
-#define I2C_NOK		1
-#define I2C_NACK	2
-#define I2C_NOK_LA	3	/* Lost arbitration */
-#define I2C_NOK_TOUT	4	/* time out */
-
-#define I2CSTAT_BSY	0x20	/* Busy bit */
-#define I2CSTAT_NACK	0x01	/* Nack bit */
-#define I2CCON_ACKGEN	0x80	/* Acknowledge generation */
-#define I2CCON_IRPND	0x10	/* Interrupt pending bit */
-#define I2C_MODE_MT	0xC0	/* Master Transmit Mode */
-#define I2C_MODE_MR	0x80	/* Master Receive Mode */
-#define I2C_START_STOP	0x20	/* START / STOP */
-#define I2C_TXRX_ENA	0x10	/* I2C Tx/Rx enable */
-
-
-/* The timeouts we live by */
-enum {
-	I2C_XFER_TIMEOUT_MS	= 35,	/* xfer to complete */
-	I2C_INIT_TIMEOUT_MS	= 1000,	/* bus free on init */
-	I2C_IDLE_TIMEOUT_MS	= 100,	/* waiting for bus idle */
-	I2C_STOP_TIMEOUT_US	= 200,	/* waiting for stop events */
-};
-
 #define I2C0_BASE	0x12c60000
-struct s3c24x0_i2c_bus i2c0 = {
-	.node = 0,
-	.bus_num = 0,
-	.regs = (struct s3c24x0_i2c *)I2C0_BASE,
-	.id = PERIPH_ID_I2C0,
-};
-
-static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
-{
-	unsigned long freq, pres = 16, div;
-
-	freq = clock_get_periph_rate(PERIPH_ID_I2C0);
-	/* calculate prescaler and divisor values */
-	if ((freq / pres / (16 + 1)) > speed)
-		/* set prescaler to 512 */
-		pres = 512;
-
-	div = 0;
-
-	while ((freq / pres / (div + 1)) > speed)
-		div++;
-
-	/* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
-	writel((div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0), &i2c->iiccon);
-
-	/* init to SLAVE REVEIVE and set slaveaddr */
-	writel(0, &i2c->iicstat);
-	writel(slaveadd, &i2c->iicadd);
-	/* program Master Transmit (and implicit STOP) */
-	writel(I2C_MODE_MT | I2C_TXRX_ENA, &i2c->iicstat);
-}
-
-static void i2c_bus_init(struct s3c24x0_i2c_bus *i2c, unsigned int bus)
-{
-//	exynos_pinmux_config(i2c->id, 0);
-	gpio_cfg_pin(GPIO_B30, EXYNOS_GPIO_FUNC(0x2));
-	gpio_cfg_pin(GPIO_B31, EXYNOS_GPIO_FUNC(0x2));
-	gpio_set_pull(GPIO_B30, EXYNOS_GPIO_PULL_NONE);
-	gpio_set_pull(GPIO_B31, EXYNOS_GPIO_PULL_NONE);
-
-	i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
-}
 
 void do_barriers(void);
 void do_barriers(void)
@@ -170,338 +101,6 @@ void my_udelay(unsigned int n)
 			  "bne 1b":"=r" (n):"0"(n));
 }
 
-void i2c_init(int speed, int slaveadd)
-{
-	struct s3c24x0_i2c_bus *i2c = &i2c0;
-	struct exynos5_gpio_part1 *gpio;
-	int i;
-	uint32_t x;
-
-#if 0
-	/* By default i2c channel 0 is the current bus */
-	g_current_bus = 0;
-
-	i2c = get_bus(g_current_bus);
-	if (!i2c)
-		return;
-#endif
-
-	i2c_bus_init(i2c, 0);
-
-	/* wait for some time to give previous transfer a chance to finish */
-	i = I2C_INIT_TIMEOUT_MS * 20;
-	while ((readl(&i2c->regs->iicstat) & I2CSTAT_BSY) && (i > 0)) {
-		my_udelay(50);
-		i--;
-	}
-
-	gpio = (struct exynos5_gpio_part1 *)(EXYNOS5_GPIO_PART1_BASE);
-	/* FIXME(dhendrix): cannot use nested macro (compilation failure) */
-//	writel((readl(&gpio->b3.con) & ~0x00FF) | 0x0022, &gpio->b3.con);
-	x = readl(&gpio->b3.con);
-	writel((x & ~0x00FF) | 0x0022, &gpio->b3.con);
-
-	i2c_ch_init(i2c->regs, speed, slaveadd);
-}
-
-static int WaitForXfer(struct s3c24x0_i2c *i2c)
-{
-	int i;
-
-	i = I2C_XFER_TIMEOUT_MS * 20;
-	while (!(readl(&i2c->iiccon) & I2CCON_IRPND)) {
-		if (i == 0) {
-			//debug("%s: i2c xfer timeout\n", __func__);
-			return I2C_NOK_TOUT;
-		}
-		my_udelay(50);
-		i--;
-	}
-
-	return I2C_OK;
-}
-
-static int IsACK(struct s3c24x0_i2c *i2c)
-{
-	return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
-}
-
-static void ReadWriteByte(struct s3c24x0_i2c *i2c)
-{
-	uint32_t x;
-
-	x = readl(&i2c->iiccon);
-	writel(x & ~I2CCON_IRPND, &i2c->iiccon);
-	/* FIXME(dhendrix): cannot use nested macro (compilation failure) */
-//	writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
-}
-
-/*
- * Verify the whether I2C ACK was received or not
- *
- * @param i2c	pointer to I2C register base
- * @param buf	array of data
- * @param len	length of data
- * return	I2C_OK when transmission done
- *		I2C_NACK otherwise
- */
-static int i2c_send_verify(struct s3c24x0_i2c *i2c, unsigned char buf[],
-			   unsigned char len)
-{
-	int i, result = I2C_OK;
-
-	if (IsACK(i2c)) {
-		for (i = 0; (i < len) && (result == I2C_OK); i++) {
-			writel(buf[i], &i2c->iicds);
-			ReadWriteByte(i2c);
-			result = WaitForXfer(i2c);
-			if (result == I2C_OK && !IsACK(i2c))
-				result = I2C_NACK;
-		}
-	} else {
-		result = I2C_NACK;
-	}
-
-	return result;
-}
-
-/*
- * Send a STOP event and wait for it to have completed
- *
- * @param mode	If it is a master transmitter or receiver
- * @return I2C_OK if the line became idle before timeout I2C_NOK_TOUT otherwise
- */
-static int i2c_send_stop(struct s3c24x0_i2c *i2c, int mode)
-{
-	int timeout;
-
-	/* Setting the STOP event to fire */
-	writel(mode | I2C_TXRX_ENA, &i2c->iicstat);
-	ReadWriteByte(i2c);
-
-	/* Wait for the STOP to send and the bus to go idle */
-	for (timeout = I2C_STOP_TIMEOUT_US; timeout > 0; timeout -= 5) {
-		if (!(readl(&i2c->iicstat) & I2CSTAT_BSY))
-			return I2C_OK;
-		my_udelay(5);
-	}
-
-	return I2C_NOK_TOUT;
-}
-
-/*
- * cmd_type is 0 for write, 1 for read.
- *
- * addr_len can take any value from 0-255, it is only limited
- * by the char, we could make it larger if needed. If it is
- * 0 we skip the address write cycle.
- */
-static int i2c_transfer(struct s3c24x0_i2c *i2c,
-			unsigned char cmd_type,
-			unsigned char chip,
-			unsigned char addr[],
-			unsigned char addr_len,
-			unsigned char data[],
-			unsigned short data_len)
-{
-	int i, result, stop_bit_result;
-	uint32_t x;
-
-	if (data == 0 || data_len == 0) {
-		/* Don't support data transfer of no length or to address 0 */
-		//debug("i2c_transfer: bad call\n");
-		return I2C_NOK;
-	}
-
-	/* Check I2C bus idle */
-	i = I2C_IDLE_TIMEOUT_MS * 20;
-	while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) {
-		my_udelay(50);
-		i--;
-	}
-
-	if (readl(&i2c->iicstat) & I2CSTAT_BSY) {
-		//debug("%s: bus busy\n", __func__);
-		return I2C_NOK_TOUT;
-	}
-
-	/* FIXME(dhendrix): cannot use nested macro (compilation failure) */
-	//writel(readl(&i2c->iiccon) | I2CCON_ACKGEN, &i2c->iiccon);
-	x = readl(&i2c->iiccon);
-	writel(x | I2CCON_ACKGEN, &i2c->iiccon);
-
-	if (addr && addr_len) {
-		writel(chip, &i2c->iicds);
-		/* send START */
-		writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
-			&i2c->iicstat);
-		if (WaitForXfer(i2c) == I2C_OK)
-			result = i2c_send_verify(i2c, addr, addr_len);
-		else
-			result = I2C_NACK;
-	} else
-		result = I2C_NACK;
-
-	switch (cmd_type) {
-	case I2C_WRITE:
-		if (result == I2C_OK)
-			result = i2c_send_verify(i2c, data, data_len);
-		else {
-			writel(chip, &i2c->iicds);
-			/* send START */
-			writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
-				&i2c->iicstat);
-			if (WaitForXfer(i2c) == I2C_OK)
-				result = i2c_send_verify(i2c, data, data_len);
-		}
-
-		if (result == I2C_OK)
-			result = WaitForXfer(i2c);
-
-		stop_bit_result = i2c_send_stop(i2c, I2C_MODE_MT);
-		break;
-
-	case I2C_READ:
-	{
-		int was_ok = (result == I2C_OK);
-
-		writel(chip, &i2c->iicds);
-		/* resend START */
-		writel(I2C_MODE_MR | I2C_TXRX_ENA |
-					I2C_START_STOP, &i2c->iicstat);
-		ReadWriteByte(i2c);
-		result = WaitForXfer(i2c);
-
-		if (was_ok || IsACK(i2c)) {
-			i = 0;
-			while ((i < data_len) && (result == I2C_OK)) {
-				/* disable ACK for final READ */
-				if (i == data_len - 1) {
-					/* FIXME(dhendrix): nested macro */
-#if 0
-					writel(readl(&i2c->iiccon) &
-					       ~I2CCON_ACKGEN,
-					       &i2c->iiccon);
-#endif
-					x = readl(&i2c->iiccon) & ~I2CCON_ACKGEN;
-					writel(x, &i2c->iiccon);
-				}
-				ReadWriteByte(i2c);
-				result = WaitForXfer(i2c);
-				data[i] = readl(&i2c->iicds);
-				i++;
-			}
-		} else {
-			result = I2C_NACK;
-		}
-
-		stop_bit_result = i2c_send_stop(i2c, I2C_MODE_MR);
-		break;
-	}
-
-	default:
-		//debug("i2c_transfer: bad call\n");
-		result = stop_bit_result = I2C_NOK;
-		break;
-	}
-
-	/*
-	 * If the transmission went fine, then only the stop bit was left to
-	 * fail.  Otherwise, the real failure we're interested in came before
-	 * that, during the actual transmission.
-	 */
-	return (result == I2C_OK) ? stop_bit_result : result;
-}
-
-
-int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
-{
-	struct s3c24x0_i2c_bus *i2c = &i2c0;
-	uchar xaddr[4];
-	int ret;
-
-	if (alen > 4) {
-		//debug("I2C read: addr len %d not supported\n", alen);
-		return 1;
-	}
-
-	if (alen > 0) {
-		xaddr[0] = (addr >> 24) & 0xFF;
-		xaddr[1] = (addr >> 16) & 0xFF;
-		xaddr[2] = (addr >> 8) & 0xFF;
-		xaddr[3] = addr & 0xFF;
-	}
-
-#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
-	/*
-	 * EEPROM chips that implement "address overflow" are ones
-	 * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
-	 * address and the extra bits end up in the "chip address"
-	 * bit slots. This makes a 24WC08 (1Kbyte) chip look like
-	 * four 256 byte chips.
-	 *
-	 * Note that we consider the length of the address field to
-	 * still be one byte because the extra address bits are
-	 * hidden in the chip address.
-	 */
-	if (alen > 0)
-		chip |= ((addr >> (alen * 8)) &
-			 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
-#endif
-	if (!i2c)
-		return -1;
-	ret = i2c_transfer(i2c->regs, I2C_READ, chip << 1, &xaddr[4 - alen],
-			   alen, buffer, len);
-	if (ret) {
-		//debug("I2c read: failed %d\n", ret);
-		return 1;
-	}
-	return 0;
-}
-
-int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
-{
-	struct s3c24x0_i2c_bus *i2c;
-	uchar xaddr[4];
-	int ret;
-
-	if (alen > 4) {
-		//debug("I2C write: addr len %d not supported\n", alen);
-		return 1;
-	}
-
-	if (alen > 0) {
-		xaddr[0] = (addr >> 24) & 0xFF;
-		xaddr[1] = (addr >> 16) & 0xFF;
-		xaddr[2] = (addr >> 8) & 0xFF;
-		xaddr[3] = addr & 0xFF;
-	}
-#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW
-	/*
-	 * EEPROM chips that implement "address overflow" are ones
-	 * like Catalyst 24WC04/08/16 which has 9/10/11 bits of
-	 * address and the extra bits end up in the "chip address"
-	 * bit slots. This makes a 24WC08 (1Kbyte) chip look like
-	 * four 256 byte chips.
-	 *
-	 * Note that we consider the length of the address field to
-	 * still be one byte because the extra address bits are
-	 * hidden in the chip address.
-	 */
-	if (alen > 0)
-		chip |= ((addr >> (alen * 8)) &
-			 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
-#endif
-	//i2c = get_bus(g_current_bus);
-	i2c = &i2c0;
-	if (!i2c)
-		return -1;
-	ret = i2c_transfer(i2c->regs, I2C_WRITE, chip << 1, &xaddr[4 - alen],
-			   alen, buffer, len);
-
-	return ret != 0;
-}
-
 /*
  * Max77686 parameters values
  * see max77686.h for parameters details
@@ -1428,6 +1027,7 @@ void bootblock_mainboard_init(void)
 {
 	/* FIXME: we should not need UART in bootblock, this is only
 	   done for testing purposes */
+	i2c_set_early_reg(I2C0_BASE);
 	i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
 	power_init();
 	clock_init();



More information about the coreboot mailing list