From 94e230aa9319ca3421867efc080c985f9bcaaef4 Mon Sep 17 00:00:00 2001 From: David Hendricks Date: Tue, 5 Feb 2013 14:50:30 -0800 Subject: [PATCH] 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 Reviewed-on: http://review.coreboot.org/2289 Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich --- 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 0f4200c770..621576dbac 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 0507fb2bda..1985662c9a 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();