coreboot-libre-fam15h-rdimm/3rdparty/chromeec/chip/mec1322/i2c.c

533 lines
14 KiB
C
Raw Normal View History

2024-03-04 11:14:53 +01:00
/* Copyright 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* I2C port module for MEC1322 */
#include "common.h"
#include "console.h"
#include "gpio.h"
#include "hooks.h"
#include "i2c.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
#include "util.h"
#define CPUTS(outstr) cputs(CC_I2C, outstr)
#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args)
#define I2C_CLOCK 16000000 /* 16 MHz */
/* Status */
#define STS_NBB BIT(0) /* Bus busy */
#define STS_LAB BIT(1) /* Arbitration lost */
#define STS_LRB BIT(3) /* Last received bit */
#define STS_BER BIT(4) /* Bus error */
#define STS_PIN BIT(7) /* Pending interrupt */
/* Control */
#define CTRL_ACK BIT(0) /* Acknowledge */
#define CTRL_STO BIT(1) /* STOP */
#define CTRL_STA BIT(2) /* START */
#define CTRL_ENI BIT(3) /* Enable interrupt */
#define CTRL_ESO BIT(6) /* Enable serial output */
#define CTRL_PIN BIT(7) /* Pending interrupt not */
/* Completion */
#define COMP_IDLE BIT(29) /* i2c bus is idle */
#define COMP_RW_BITS_MASK 0x3C /* R/W bits mask */
/* Maximum transfer of a SMBUS block transfer */
#define SMBUS_MAX_BLOCK_SIZE 32
/*
* Amount of time to blocking wait for i2c bus to finish. After this blocking
* timeout, if the bus is still not finished, then allow other tasks to run.
* Note: this is just long enough for a 400kHz bus to finish transmitting one
* byte assuming the bus isn't being held.
*/
#define I2C_WAIT_BLOCKING_TIMEOUT_US 25
enum i2c_transaction_state {
/* Stop condition was sent in previous transaction */
I2C_TRANSACTION_STOPPED,
/* Stop condition was not sent in previous transaction */
I2C_TRANSACTION_OPEN,
};
/* I2C controller state data */
static struct {
/* Transaction timeout, or 0 to use default. */
uint32_t timeout_us;
/* Task waiting on port, or TASK_ID_INVALID if none. */
volatile task_id_t task_waiting;
enum i2c_transaction_state transaction_state;
} cdata[I2C_CONTROLLER_COUNT];
/* Map port number to port name in datasheet, for debug prints. */
static const char *i2c_port_names[MEC1322_I2C_PORT_COUNT] = {
[MEC1322_I2C0_0] = "0_0",
[MEC1322_I2C0_1] = "0_1",
[MEC1322_I2C1] = "1",
[MEC1322_I2C2] = "2",
[MEC1322_I2C3] = "3",
};
static void configure_controller_speed(int controller, int kbps)
{
int t_low, t_high;
const int period = I2C_CLOCK / 1000 / kbps;
/*
* Refer to NXP UM10204 for minimum timing requirement of T_Low and
* T_High.
* http://www.nxp.com/documents/user_manual/UM10204.pdf
*/
if (kbps > 400) {
/* Fast mode plus */
t_low = t_high = period / 2 - 1;
MEC1322_I2C_DATA_TIM(controller) = 0x06060601;
MEC1322_I2C_DATA_TIM_2(controller) = 0x06;
} else if (kbps > 100) {
/* Fast mode */
/* By spec, clk low period is 1.3us min */
t_low = MAX((int)(I2C_CLOCK * 1.3 / 1000000), period / 2 - 1);
t_high = period - t_low - 2;
MEC1322_I2C_DATA_TIM(controller) = 0x040a0a01;
MEC1322_I2C_DATA_TIM_2(controller) = 0x0a;
} else {
/* Standard mode */
t_low = t_high = period / 2 - 1;
MEC1322_I2C_DATA_TIM(controller) = 0x0c4d5006;
MEC1322_I2C_DATA_TIM_2(controller) = 0x4d;
}
/* Clock periods is one greater than the contents of these fields */
MEC1322_I2C_BUS_CLK(controller) = ((t_high & 0xff) << 8) |
(t_low & 0xff);
}
static void configure_controller(int controller, int kbps)
{
MEC1322_I2C_CTRL(controller) = CTRL_PIN;
MEC1322_I2C_OWN_ADDR(controller) = 0x0;
configure_controller_speed(controller, kbps);
MEC1322_I2C_CTRL(controller) = CTRL_PIN | CTRL_ESO |
CTRL_ACK | CTRL_ENI;
MEC1322_I2C_CONFIG(controller) |= BIT(10); /* ENAB */
/* Enable interrupt */
MEC1322_I2C_CONFIG(controller) |= BIT(29); /* ENIDI */
MEC1322_INT_ENABLE(12) |= BIT(controller);
MEC1322_INT_BLK_EN |= BIT(12);
}
static void reset_controller(int controller)
{
int i;
MEC1322_I2C_CONFIG(controller) |= BIT(9);
udelay(100);
MEC1322_I2C_CONFIG(controller) &= ~BIT(9);
for (i = 0; i < i2c_ports_used; ++i)
if (controller == i2c_port_to_controller(i2c_ports[i].port)) {
configure_controller(controller, i2c_ports[i].kbps);
cdata[controller].transaction_state =
I2C_TRANSACTION_STOPPED;
break;
}
}
static int wait_for_interrupt(int controller, int timeout)
{
int event;
if (timeout <= 0)
return EC_ERROR_TIMEOUT;
cdata[controller].task_waiting = task_get_current();
task_enable_irq(MEC1322_IRQ_I2C_0 + controller);
/* Wait until I2C interrupt or timeout. */
event = task_wait_event_mask(TASK_EVENT_I2C_IDLE, timeout);
task_disable_irq(MEC1322_IRQ_I2C_0 + controller);
cdata[controller].task_waiting = TASK_ID_INVALID;
return (event & TASK_EVENT_TIMER) ? EC_ERROR_TIMEOUT : EC_SUCCESS;
}
static int wait_idle(int controller)
{
uint8_t sts = MEC1322_I2C_STATUS(controller);
uint64_t block_timeout = get_time().val + I2C_WAIT_BLOCKING_TIMEOUT_US;
uint64_t task_timeout = block_timeout + cdata[controller].timeout_us;
int rv = 0;
while (!(sts & STS_NBB)) {
if (rv)
return rv;
if (get_time().val > block_timeout)
rv = wait_for_interrupt(controller,
task_timeout - get_time().val);
sts = MEC1322_I2C_STATUS(controller);
}
if (sts & (STS_BER | STS_LAB))
return EC_ERROR_UNKNOWN;
return EC_SUCCESS;
}
static int wait_byte_done(int controller)
{
uint8_t sts = MEC1322_I2C_STATUS(controller);
uint64_t block_timeout = get_time().val + I2C_WAIT_BLOCKING_TIMEOUT_US;
uint64_t task_timeout = block_timeout + cdata[controller].timeout_us;
int rv = 0;
while (sts & STS_PIN) {
if (rv)
return rv;
if (get_time().val > block_timeout)
rv = wait_for_interrupt(controller,
task_timeout - get_time().val);
sts = MEC1322_I2C_STATUS(controller);
}
return sts & STS_LRB;
}
static void select_port(int port)
{
/*
* I2C0_1 uses port 1 of controller 0. All other I2C pin sets
* use port 0.
*/
uint8_t port_sel = (port == MEC1322_I2C0_1) ? 1 : 0;
int controller = i2c_port_to_controller(port);
MEC1322_I2C_CONFIG(controller) &= ~0xf;
MEC1322_I2C_CONFIG(controller) |= port_sel;
}
static inline int get_line_level(int controller)
{
int ret, ctrl;
/*
* We need to enable BB (Bit Bang) mode in order to read line level
* properly, othervise line levels return always idle (0x60).
*/
ctrl = MEC1322_I2C_BB_CTRL(controller);
MEC1322_I2C_BB_CTRL(controller) |= 1;
ret = (MEC1322_I2C_BB_CTRL(controller) >> 5) & 0x3;
MEC1322_I2C_BB_CTRL(controller) = ctrl;
return ret;
}
static inline void push_in_buf(uint8_t **in, uint8_t val, int skip)
{
if (!skip) {
**in = val;
(*in)++;
}
}
int chip_i2c_xfer(const int port,
const uint16_t slave_addr_flags,
const uint8_t *out, int out_size,
uint8_t *in, int in_size, int flags)
{
int i;
int controller;
int send_start = flags & I2C_XFER_START;
int send_stop = flags & I2C_XFER_STOP;
int skip = 0;
int bytes_to_read;
uint8_t reg;
int ret_done;
if (out_size == 0 && in_size == 0)
return EC_SUCCESS;
select_port(port);
controller = i2c_port_to_controller(port);
if (send_start &&
cdata[controller].transaction_state == I2C_TRANSACTION_STOPPED)
wait_idle(controller);
reg = MEC1322_I2C_STATUS(controller);
if (send_start &&
cdata[controller].transaction_state == I2C_TRANSACTION_STOPPED &&
(((reg & (STS_BER | STS_LAB)) || !(reg & STS_NBB)) ||
(get_line_level(controller)
!= I2C_LINE_IDLE))) {
CPRINTS("i2c%s bad status 0x%02x, SCL=%d, SDA=%d",
i2c_port_names[port], reg,
get_line_level(controller) & I2C_LINE_SCL_HIGH,
get_line_level(controller) & I2C_LINE_SDA_HIGH);
/* Attempt to unwedge the port. */
i2c_unwedge(port);
/* Bus error, bus busy, or arbitration lost. Try reset. */
reset_controller(controller);
select_port(port);
/*
* We don't know what edges the slave saw, so sleep long enough
* that the slave will see the new start condition below.
*/
usleep(1000);
}
if (out_size) {
if (send_start) {
MEC1322_I2C_DATA(controller) =
(uint8_t)(I2C_GET_ADDR(slave_addr_flags)
<< 1);
/* Clock out the slave address, sending START bit */
MEC1322_I2C_CTRL(controller) = CTRL_PIN | CTRL_ESO |
CTRL_ENI | CTRL_ACK |
CTRL_STA;
cdata[controller].transaction_state =
I2C_TRANSACTION_OPEN;
}
for (i = 0; i < out_size; ++i) {
ret_done = wait_byte_done(controller);
if (ret_done)
goto err_chip_i2c_xfer;
MEC1322_I2C_DATA(controller) = out[i];
}
ret_done = wait_byte_done(controller);
if (ret_done)
goto err_chip_i2c_xfer;
/*
* Send STOP bit if the stop flag is on, and caller
* doesn't expect to receive data.
*/
if (send_stop && in_size == 0) {
MEC1322_I2C_CTRL(controller) = CTRL_PIN | CTRL_ESO |
CTRL_STO | CTRL_ACK;
cdata[controller].transaction_state =
I2C_TRANSACTION_STOPPED;
}
}
if (in_size) {
/* Resend start bit when changing direction */
if (out_size || send_start) {
/* Repeated start case */
if (cdata[controller].transaction_state ==
I2C_TRANSACTION_OPEN)
MEC1322_I2C_CTRL(controller) = CTRL_ESO |
CTRL_STA |
CTRL_ACK |
CTRL_ENI;
MEC1322_I2C_DATA(controller) =
(uint8_t)(I2C_GET_ADDR(slave_addr_flags)
<< 1)
| 0x01;
/* New transaction case, clock out slave address. */
if (cdata[controller].transaction_state ==
I2C_TRANSACTION_STOPPED)
MEC1322_I2C_CTRL(controller) = CTRL_ESO |
CTRL_STA |
CTRL_ACK |
CTRL_ENI |
CTRL_PIN;
cdata[controller].transaction_state =
I2C_TRANSACTION_OPEN;
/* Skip over the dummy byte */
skip = 1;
in_size++;
}
/* Special flags need to be set for last two bytes */
bytes_to_read = send_stop ? in_size - 2 : in_size;
for (i = 0; i < bytes_to_read; ++i) {
ret_done = wait_byte_done(controller);
if (ret_done)
goto err_chip_i2c_xfer;
push_in_buf(&in, MEC1322_I2C_DATA(controller), skip);
skip = 0;
}
ret_done = wait_byte_done(controller);
if (ret_done)
goto err_chip_i2c_xfer;
if (send_stop) {
/*
* De-assert ACK bit before reading the next to last
* byte, so that the last byte is NACK'ed.
*/
MEC1322_I2C_CTRL(controller) = CTRL_ESO | CTRL_ENI;
push_in_buf(&in, MEC1322_I2C_DATA(controller), skip);
ret_done = wait_byte_done(controller);
if (ret_done)
goto err_chip_i2c_xfer;
/* Send STOP */
MEC1322_I2C_CTRL(controller) =
CTRL_PIN | CTRL_ESO | CTRL_ACK | CTRL_STO;
cdata[controller].transaction_state =
I2C_TRANSACTION_STOPPED;
/*
* We need to know our stop point two bytes in
* advance. If we don't know soon enough, we need
* to do an extra dummy read (to last_addr + 1) to
* issue the stop.
*/
push_in_buf(&in, MEC1322_I2C_DATA(controller),
in_size == 1);
}
}
/* Check for error conditions */
if (MEC1322_I2C_STATUS(controller) & (STS_LAB | STS_BER))
return EC_ERROR_UNKNOWN;
return EC_SUCCESS;
err_chip_i2c_xfer:
/* Send STOP and return error */
MEC1322_I2C_CTRL(controller) = CTRL_PIN | CTRL_ESO |
CTRL_STO | CTRL_ACK;
cdata[controller].transaction_state = I2C_TRANSACTION_STOPPED;
if (ret_done == STS_LRB)
return EC_ERROR_BUSY;
else if (ret_done == EC_ERROR_TIMEOUT) {
/*
* If our transaction timed out then our i2c controller
* may be wedged without showing any other outward signs
* of failure. Reset the controller so that future
* transactions have a chance of success.
*/
reset_controller(controller);
return EC_ERROR_TIMEOUT;
}
else
return EC_ERROR_UNKNOWN;
}
int i2c_raw_get_scl(int port)
{
enum gpio_signal g;
/* If no SCL pin defined for this port, then return 1 to appear idle. */
if (get_scl_from_i2c_port(port, &g) != EC_SUCCESS)
return 1;
return gpio_get_level(g);
}
int i2c_raw_get_sda(int port)
{
enum gpio_signal g;
/* If no SDA pin defined for this port, then return 1 to appear idle. */
if (get_sda_from_i2c_port(port, &g) != EC_SUCCESS)
return 1;
return gpio_get_level(g);
}
int i2c_get_line_levels(int port)
{
int rv;
i2c_lock(port, 1);
select_port(port);
rv = get_line_level(i2c_port_to_controller(port));
i2c_lock(port, 0);
return rv;
}
int i2c_port_to_controller(int port)
{
if (port < 0 || port >= MEC1322_I2C_PORT_COUNT)
return -1;
return (port == MEC1322_I2C0_0) ? 0 : port - 1;
}
void i2c_set_timeout(int port, uint32_t timeout)
{
/* Param is port, but timeout is stored by-controller. */
cdata[i2c_port_to_controller(port)].timeout_us =
timeout ? timeout : I2C_TIMEOUT_DEFAULT_US;
}
static void i2c_init(void)
{
int i;
int controller;
int controller0_kbps = -1;
/* Configure GPIOs */
gpio_config_module(MODULE_I2C, 1);
for (i = 0; i < i2c_ports_used; ++i) {
/*
* If this controller has multiple ports, check if we already
* configured it. If so, ensure previously configured bitrate
* matches.
*/
controller = i2c_port_to_controller(i2c_ports[i].port);
if (controller == 0) {
if (controller0_kbps != -1) {
ASSERT(controller0_kbps == i2c_ports[i].kbps);
continue;
}
controller0_kbps = i2c_ports[i].kbps;
}
configure_controller(controller, i2c_ports[i].kbps);
cdata[controller].task_waiting = TASK_ID_INVALID;
cdata[controller].transaction_state = I2C_TRANSACTION_STOPPED;
/* Use default timeout. */
i2c_set_timeout(i2c_ports[i].port, 0);
}
}
DECLARE_HOOK(HOOK_INIT, i2c_init, HOOK_PRIO_INIT_I2C);
static void handle_interrupt(int controller)
{
int id = cdata[controller].task_waiting;
/* Clear the interrupt status */
MEC1322_I2C_COMPLETE(controller) &= (COMP_RW_BITS_MASK | COMP_IDLE);
/*
* Write to control register interferes with I2C transaction.
* Instead, let's disable IRQ from the core until the next time
* we want to wait for STS_PIN/STS_NBB.
*/
task_disable_irq(MEC1322_IRQ_I2C_0 + controller);
/* Wake up the task which was waiting on the I2C interrupt, if any. */
if (id != TASK_ID_INVALID)
task_set_event(id, TASK_EVENT_I2C_IDLE, 0);
}
void i2c0_interrupt(void) { handle_interrupt(0); }
void i2c1_interrupt(void) { handle_interrupt(1); }
void i2c2_interrupt(void) { handle_interrupt(2); }
void i2c3_interrupt(void) { handle_interrupt(3); }
DECLARE_IRQ(MEC1322_IRQ_I2C_0, i2c0_interrupt, 2);
DECLARE_IRQ(MEC1322_IRQ_I2C_1, i2c1_interrupt, 2);
DECLARE_IRQ(MEC1322_IRQ_I2C_2, i2c2_interrupt, 2);
DECLARE_IRQ(MEC1322_IRQ_I2C_3, i2c3_interrupt, 2);