110800SN/A/*
210800SN/A * Copyright (c) 2012 ARM Limited
310800SN/A * All rights reserved
410800SN/A *
510800SN/A * The license below extends only to copyright in the software and shall
610800SN/A * not be construed as granting a license to any other intellectual
710800SN/A * property including but not limited to intellectual property relating
810800SN/A * to a hardware implementation of the functionality of the software
910800SN/A * licensed hereunder.  You may use the software subject to the license
1010800SN/A * terms below provided that you ensure that this notice is replicated
1110800SN/A * unmodified and in its entirety in all distributions of the software,
1210800SN/A * modified or unmodified, in source code or in binary form.
1310800SN/A *
1410800SN/A * Redistribution and use in source and binary forms, with or without
1510800SN/A * modification, are permitted provided that the following conditions are
1610800SN/A * met: redistributions of source code must retain the above copyright
1710800SN/A * notice, this list of conditions and the following disclaimer;
1810800SN/A * redistributions in binary form must reproduce the above copyright
1910800SN/A * notice, this list of conditions and the following disclaimer in the
2010800SN/A * documentation and/or other materials provided with the distribution;
2110800SN/A * neither the name of the copyright holders nor the names of its
2210800SN/A * contributors may be used to endorse or promote products derived from
2310800SN/A * this software without specific prior written permission.
2410800SN/A *
2510800SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2610800SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2710800SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2810800SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2910800SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3010800SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3110800SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3210800SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3310800SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3410800SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3510800SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3610800SN/A *
3710800SN/A * Authors: Peter Enns
3810800SN/A */
3910800SN/A
4011262Sandreas.sandberg@arm.com#include "dev/i2c/bus.hh"
4110800SN/A
4210800SN/A#include "debug/Checkpoint.hh"
4311262Sandreas.sandberg@arm.com#include "dev/i2c/device.hh"
4410800SN/A#include "mem/packet_access.hh"
4510800SN/A
4610800SN/A// clang complains about std::set being overloaded with Packet::set if
4710800SN/A// we open up the entire namespace std
4810800SN/Ausing std::vector;
4910800SN/Ausing std::map;
5010800SN/A
5110800SN/A/**
5210800SN/A * 4KB - see e.g.
5310800SN/A * http://infocenter.arm.com/help/topic/com.arm.doc.dui0440b/Bbajihec.html
5410800SN/A */
5510800SN/AI2CBus::I2CBus(const I2CBusParams *p)
5612772Snikos.nikoleris@arm.com    : BasicPioDevice(p, 0x1000), scl(1), sda(1), state(IDLE), currBit(7),
5710800SN/A      i2cAddr(0x00), message(0x00)
5810800SN/A{
5910800SN/A    vector<I2CDevice*> devs = p->devices;
6010800SN/A
6110800SN/A    for (auto d : p->devices) {
6210800SN/A        devices[d->i2cAddr()] = d;
6310800SN/A    }
6410800SN/A}
6510800SN/A
6610800SN/A/**
6710800SN/A * Reads will always be to SB_CONTROLS. The kernel wants to know the state
6810800SN/A * of sda and scl.
6910800SN/A */
7010800SN/ATick
7110800SN/AI2CBus::read(PacketPtr pkt)
7210800SN/A{
7310800SN/A    assert(pkt->getAddr() == pioAddr + SB_CONTROLS);
7410800SN/A
7513342Sgabeblack@google.com    pkt->setRaw<uint8_t>((sda << 1) | scl);
7610800SN/A    pkt->makeAtomicResponse();
7710800SN/A    return pioDelay;
7810800SN/A}
7910800SN/A
8010800SN/A/**
8110800SN/A * The default i2c bus driver used by the realview pbx board writes to
8210800SN/A * this device one bit at a time. To facilitate making new i2c devices,
8310800SN/A * i2cBus::write takes care of the low-level details of the i2c protocol.
8410800SN/A * See the I2C Specification [1] for a detailed description of the
8510800SN/A * protocol.
8610800SN/A *
8710800SN/A * [1] - http://www.nxp.com/documents/user_manual/UM10204.pdf
8810800SN/A */
8910800SN/ATick
9010800SN/AI2CBus::write(PacketPtr pkt)
9110800SN/A{
9210800SN/A    assert(pkt->getAddr() == pioAddr + SB_CONTROLS ||
9310800SN/A           pkt->getAddr() == pioAddr + SB_CONTROLC);
9410800SN/A
9510800SN/A    updateSignals(pkt);
9610800SN/A
9710800SN/A    // Check if the bus master is starting a new transmission.
9810800SN/A    if (isStart(pkt)) {
9910800SN/A        state = RECEIVING_ADDR;
10010800SN/A        message = 0x00;
10110800SN/A        currBit = 7;
10210800SN/A        /* Most i2c devices expect something special (e.g., command,
10310800SN/A         * register address) in the first byte they receive so they
10410800SN/A         * must be notified somehow that this is a new transmission.
10510800SN/A         */
10610800SN/A        for (auto& d : devices) {
10710800SN/A            d.second->i2cStart();
10810800SN/A        }
10910800SN/A        return pioDelay;
11010800SN/A    }
11110800SN/A
11210800SN/A    // Check if the bus master is ending a transmission.
11310800SN/A    if (isEnd(pkt)) {
11410800SN/A        state = IDLE;
11510800SN/A        return pioDelay;
11610800SN/A    }
11710800SN/A
11810800SN/A    // Only change state when the clock is transitioning from low to high.
11910800SN/A    // This may not perfectly mimic physical i2c devices but the important
12010800SN/A    // part is to only do the following once per clock cycle.
12110800SN/A    if (isClockSet(pkt)) {
12210800SN/A        switch (state) {
12310800SN/A          case RECEIVING_ADDR:
12410800SN/A            if (currBit >= 0) {
12510800SN/A                message |= sda << currBit;
12610800SN/A                currBit--;
12710800SN/A            } else {
12810800SN/A                i2cAddr = message >> 1;
12910800SN/A                assert(devices.find(i2cAddr) != devices.end());
13010800SN/A                if (message & 0x01) {
13110800SN/A                    state = SENDING_DATA;
13210800SN/A                    message = devices[i2cAddr]->read();
13310800SN/A                } else {
13410800SN/A                    state = RECEIVING_DATA;
13510800SN/A                    message = 0x00;
13610800SN/A                }
13710800SN/A                currBit = 7;
13810800SN/A                sda = 0; /* Ack */
13910800SN/A            }
14010800SN/A            break;
14110800SN/A          case RECEIVING_DATA:
14210800SN/A            if (currBit >= 0) {
14310800SN/A                message |= sda << currBit;
14410800SN/A                currBit--;
14510800SN/A            } else {
14610800SN/A                devices[i2cAddr]->write(message);
14710800SN/A                message = 0x00;
14810800SN/A                currBit = 7;
14910800SN/A                sda = 0; /* Ack */
15010800SN/A            }
15110800SN/A            break;
15210800SN/A          case SENDING_DATA:
15310800SN/A            if (currBit >= 0) {
15410800SN/A                sda = (message >> currBit) & 0x01;
15510800SN/A                currBit--;
15610800SN/A            } else {
15710800SN/A                if (!sda) /* Check for ack from the bus master. */
15810800SN/A                    message = devices[i2cAddr]->read();
15910800SN/A                currBit = 7;
16010800SN/A            }
16110800SN/A            break;
16210800SN/A          case IDLE:
16310800SN/A          default:
16410800SN/A            panic("Invalid state on posedge of clock in I2CBus::write.\n");
16510800SN/A            break;
16610800SN/A        }
16710800SN/A    }
16810800SN/A
16910800SN/A    return pioDelay;
17010800SN/A}
17110800SN/A
17210800SN/Avoid
17310800SN/AI2CBus::updateSignals(PacketPtr pkt)
17410800SN/A{
17513342Sgabeblack@google.com    uint8_t msg = pkt->getRaw<uint8_t>();
17610800SN/A    Addr daddr = pkt->getAddr() - pioAddr;
17710800SN/A
17810800SN/A    switch (daddr) {
17910800SN/A      case SB_CONTROLS:
18010800SN/A        scl = (msg & 1) ? 1 : scl;
18110800SN/A        sda = (msg & 2) ? 1 : sda;
18210800SN/A        break;
18310800SN/A      case SB_CONTROLC:
18410800SN/A        scl = (msg & 1) ? 0 : scl;
18510800SN/A        sda = (msg & 2) ? 0 : sda;
18610800SN/A        break;
18710800SN/A      default:
18810800SN/A        break;
18910800SN/A    }
19010800SN/A}
19110800SN/A
19210800SN/Abool
19310800SN/AI2CBus::isClockSet(PacketPtr pkt) const
19410800SN/A{
19513342Sgabeblack@google.com    uint8_t msg = pkt->getRaw<uint8_t>();
19610800SN/A    Addr daddr = pkt->getAddr() - pioAddr;
19710800SN/A    return daddr == SB_CONTROLS && (msg & 1);
19810800SN/A}
19910800SN/A
20010800SN/Abool
20110800SN/AI2CBus::isStart(PacketPtr pkt) const
20210800SN/A{
20313342Sgabeblack@google.com    uint8_t msg = pkt->getRaw<uint8_t>();
20410800SN/A    Addr daddr = pkt->getAddr() - pioAddr;
20510800SN/A    return scl && (msg & 2) && daddr == SB_CONTROLC;
20610800SN/A}
20710800SN/A
20810800SN/Abool
20910800SN/AI2CBus::isEnd(PacketPtr pkt) const
21010800SN/A{
21113342Sgabeblack@google.com    uint8_t msg = pkt->getRaw<uint8_t>();
21210800SN/A    Addr daddr = pkt->getAddr() - pioAddr;
21310800SN/A    return scl && (msg & 2) && daddr == SB_CONTROLS;
21410800SN/A}
21510800SN/Avoid
21610905SN/AI2CBus::serialize(CheckpointOut &cp) const
21710800SN/A{
21810800SN/A    DPRINTF(Checkpoint, "Serializing I2C bus.\n");
21910800SN/A    SERIALIZE_SCALAR(scl);
22010800SN/A    SERIALIZE_SCALAR(sda);
22110800SN/A    SERIALIZE_ENUM(state);
22210800SN/A    SERIALIZE_SCALAR(currBit);
22310800SN/A    SERIALIZE_SCALAR(i2cAddr);
22410800SN/A    SERIALIZE_SCALAR(message);
22510800SN/A}
22610800SN/A
22710800SN/Avoid
22810905SN/AI2CBus::unserialize(CheckpointIn &cp)
22910800SN/A{
23010800SN/A    DPRINTF(Checkpoint, "Unserializing I2C bus.\n");
23110800SN/A    UNSERIALIZE_SCALAR(scl);
23210800SN/A    UNSERIALIZE_SCALAR(sda);
23310800SN/A    UNSERIALIZE_ENUM(state);
23410800SN/A    UNSERIALIZE_SCALAR(currBit);
23510800SN/A    UNSERIALIZE_SCALAR(i2cAddr);
23610800SN/A    UNSERIALIZE_SCALAR(message);
23710800SN/A}
23810800SN/A
23910800SN/AI2CBus*
24010800SN/AI2CBusParams::create()
24110800SN/A{
24210800SN/A    return new I2CBus(this);
24310800SN/A}
244