blob: e1f6394817e913d5dd3f73aadd30e47600871e30 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_DEVICES_I2C_DRIVERS_INTEL_I2C_INTEL_I2C_CONTROLLER_H_
#define SRC_DEVICES_I2C_DRIVERS_INTEL_I2C_INTEL_I2C_CONTROLLER_H_
#include <lib/device-protocol/pci.h>
#include <lib/mmio/mmio.h>
#include <lib/zircon-internal/thread_annotations.h>
#include <lib/zx/event.h>
#include <lib/zx/interrupt.h>
#include <stdint.h>
#include <threads.h>
#include <zircon/listnode.h>
#include <zircon/types.h>
#include <map>
#include <optional>
#include <ddk/device.h>
#include <ddk/mmio-buffer.h>
#include <ddktl/device.h>
#include <ddktl/protocol/i2cimpl.h>
#include <ddktl/protocol/pci.h>
#include "intel-i2c-subordinate.h"
namespace intel_i2c {
struct __attribute__((packed)) I2cRegs {
uint32_t ctl;
uint32_t tar_add;
uint32_t _reserved0[2];
uint32_t data_cmd;
uint32_t ss_scl_hcnt;
uint32_t ss_scl_lcnt;
uint32_t fs_scl_hcnt;
uint32_t fs_scl_lcnt;
uint32_t _reserved1[2];
uint32_t intr_stat;
uint32_t intr_mask;
uint32_t raw_intr_stat;
uint32_t rx_tl;
uint32_t tx_tl;
uint32_t clr_intr;
uint32_t clr_rx_under;
uint32_t clr_rx_over;
uint32_t clr_tx_over;
uint32_t _reserved2[1];
uint32_t clr_tx_abort;
uint32_t _reserved3[1];
uint32_t clr_activity;
uint32_t clr_stop_det;
uint32_t clr_start_det;
uint32_t clr_gen_call;
uint32_t i2c_en;
uint32_t i2c_sta;
uint32_t txflr;
uint32_t rxflr;
uint32_t sda_hold;
uint32_t tx_abrt_source;
uint32_t slv_data_nack;
uint32_t dma_ctrl;
uint32_t dma_tdlr;
uint32_t dma_rdlr;
uint32_t sda_setup;
uint32_t ack_gen_call;
uint32_t enable_status;
uint32_t _reserved4[21];
uint32_t comp_param1;
uint32_t comp_ver;
uint32_t comp_type;
};
_Static_assert(sizeof(I2cRegs) <= 0x200, "bad struct");
inline constexpr uint32_t kI2cMaxFastPlusSpeedHz = 1000000;
inline constexpr uint32_t kI2cMaxFastSpeedHz = 400000;
inline constexpr uint32_t kI2cMaxStandardSpeedHz = 100000;
inline constexpr uint32_t kI2cEnAbort = 1;
inline constexpr uint32_t kI2cEnEnable = 0;
inline constexpr uint32_t kCtlSlaveDisable = 6;
inline constexpr uint32_t kCtlRestartEnable = 5;
inline constexpr uint32_t kCtlAddressingMode = 4;
inline constexpr uint32_t kCtlAddressingMode7Bit = 0x0;
inline constexpr uint32_t kCtlAddressingMode10Bit = 0x1;
inline constexpr uint32_t kCtlSpeed = 1;
inline constexpr uint32_t kCtlSpeedStandard = 0x1;
inline constexpr uint32_t kCtlSpeedFast = 0x2;
inline constexpr uint32_t kCtlMasterMode = 0;
inline constexpr uint32_t kCtlMasterModeEnabled = 0x1;
inline constexpr uint32_t kIntrGeneralCall = 11;
inline constexpr uint32_t kIntrStartDetection = 10;
inline constexpr uint32_t kIntrStopDetection = 9;
inline constexpr uint32_t kIntrActivity = 8;
inline constexpr uint32_t kIntrTxAbort = 6;
inline constexpr uint32_t kIntrTxEmpty = 4;
inline constexpr uint32_t kIntrTxOver = 3;
inline constexpr uint32_t kIntrRxFull = 2;
inline constexpr uint32_t kIntrRxOver = 1;
inline constexpr uint32_t kIntrRxUnder = 0;
inline constexpr uint32_t kTarAddWidth = 12;
inline constexpr uint32_t kTarAddWidth7Bit = 0x0;
inline constexpr uint32_t kTarAddWidth10Bit = 0x1;
inline constexpr uint32_t kTarAddSpecial = 11;
inline constexpr uint32_t kTarAddGcOrStart = 10;
inline constexpr uint32_t kTarAddIcTar = 0;
inline constexpr uint32_t kI2cStaCa = 5;
inline constexpr uint32_t kI2cStaRfcf = 4;
inline constexpr uint32_t kI2cStaRfne = 3;
inline constexpr uint32_t kI2cStaTfce = 2;
inline constexpr uint32_t kI2cStaTfnf = 1;
inline constexpr uint32_t kI2cStaActivity = 0;
inline constexpr uint32_t kDataCmdRestart = 10;
inline constexpr uint32_t kDataCmdStop = 9;
inline constexpr uint32_t kDataCmdCmd = 8;
inline constexpr uint32_t kDataCmdCmdWrite = 0;
inline constexpr uint32_t kDataCmdCmdRead = 1;
inline constexpr uint32_t kDataCmdDat = 0;
class IntelI2cController;
using IntelI2cControllerType =
ddk::Device<IntelI2cController, ddk::Initializable, ddk::Unbindable>;
class IntelI2cController : public IntelI2cControllerType,
public ddk::I2cImplProtocol<IntelI2cController, ddk::base_protocol> {
public:
IntelI2cController(zx_device_t* parent) : IntelI2cControllerType(parent), pci_(parent) {}
static zx_status_t Create(void* ctx, zx_device_t* parent);
void DdkInit(ddk::InitTxn txn);
zx_status_t Reset() TA_REQ(mutex_);
zx_status_t WaitForRxFull(const zx::time deadline);
zx_status_t WaitForTxEmpty(const zx::time deadline);
zx_status_t WaitForStopDetect(const zx::time deadline);
zx_status_t ClearStopDetect();
zx_status_t CheckForError();
// Acts on the DATA_CMD register, and clear
// interrupt masks as appropriate
zx_status_t IssueRx(const uint32_t data_cmd);
zx_status_t FlushRxFullIrq();
uint8_t ReadRx();
zx_status_t IssueTx(const uint32_t data_cmd);
void Enable();
uint8_t GetRxFifoDepth() const { return rx_fifo_depth_; }
zx_status_t SetRxFifoThreshold(const uint32_t threshold);
uint32_t GetRxFifoLevel();
bool IsRxFifoEmpty();
bool IsTxFifoFull();
bool IsBusIdle();
uint32_t StopDetected();
void SetAddressingMode(const uint32_t addr_mode_bit);
void SetTargetAddress(const uint32_t addr_mode_bit, const uint32_t address);
uint32_t I2cImplGetBusCount();
zx_status_t I2cImplGetMaxTransferSize(const uint32_t bus_id, size_t* out_size);
zx_status_t I2cImplSetBitrate(const uint32_t bus_id, const uint32_t bitrate);
zx_status_t I2cImplTransact(const uint32_t bus_id, const i2c_impl_op_t* op_list,
const size_t op_count);
void DdkUnbind(ddk::UnbindTxn txn);
void DdkRelease();
private:
zx_status_t Init();
ddk::Pci pci_;
thrd_t irq_thread_;
zx::interrupt irq_handle_;
zx::event event_handle_;
int IrqThread();
zx_status_t DeviceSpecificInit(const uint16_t device_id);
zx_status_t ComputeBusTiming();
uint32_t GetRxFifoThreshold();
uint32_t GetTxFifoThreshold();
zx_status_t SetTxFifoThreshold(const uint32_t threshold);
zx_status_t SetBusFrequency(const uint32_t frequency);
zx_status_t AddSubordinates();
zx_status_t AddSubordinate(const uint8_t width, const uint16_t address,
const zx_device_prop_t* props, const uint32_t propcount);
static uint32_t ComputeSclHcnt(const uint32_t controller_freq, const uint32_t t_high_nanos,
const uint32_t t_r_nanos);
static uint32_t ComputeSclLcnt(const uint32_t controller_freq, const uint32_t t_low_nanos,
const uint32_t t_f_nanos);
static uint8_t ExtractTxFifoDepthFromParam(const uint32_t param);
static uint8_t ExtractRxFifoDepthFromParam(const uint32_t param);
static uint32_t ChipAddrMask(const int width);
MMIO_PTR I2cRegs* regs_;
MMIO_PTR volatile uint32_t* soft_reset_;
mtx_t mutex_;
uint8_t rx_fifo_depth_;
std::optional<ddk::MmioBuffer> mmio_;
uint32_t controller_freq_;
uint32_t bus_freq_;
// Bus parameters
uint16_t sda_hold_;
// Standard speed parameters
uint16_t ss_scl_hcnt_;
uint16_t ss_scl_lcnt_;
// Fast mode speed parameters
uint16_t fs_scl_hcnt_;
uint16_t fs_scl_lcnt_;
// Fast mode plus speed parameters
uint16_t fmp_scl_hcnt_;
uint16_t fmp_scl_lcnt_;
uint8_t tx_fifo_depth_;
std::map<uint16_t, std::unique_ptr<IntelI2cSubordinate>> subordinates_ TA_GUARDED(mutex_);
mtx_t irq_mask_mutex_;
};
} // namespace intel_i2c
#endif // SRC_DEVICES_I2C_DRIVERS_INTEL_I2C_INTEL_I2C_CONTROLLER_H_