/** @file
 *
 *  Copyright (c) 2021 Rockchip Electronics Co., Ltd.
 *  Copyright (c) 2023, Mario Bălănică <mariobalanica02@gmail.com>
 *
 *  SPDX-License-Identifier: BSD-2-Clause-Patent
 *
 **/

#ifndef __RK_I2C_DXE_H__
#define __RK_I2C_DXE_H__

#include <Uefi.h>

#define I2C_PERIPHERAL_SIZE  0x1000

#define I2C_SLAVE_ADDR    0x00
#define I2C_EXT_SLAVE_ADDR  0x10
#define I2C_DATA    0x04

#define I2C_CONTROL    0x08
#define I2C_CONTROL_ACK  (1 << 2)
#define I2C_CONTROL_IFLG  (1 << 3)
#define I2C_CONTROL_STOP  (1 << 4)
#define I2C_CONTROL_START  (1 << 5)
#define I2C_CONTROL_I2CEN  (1 << 6)
#define I2C_CONTROL_INTEN  (1 << 7)

#define I2C_STATUS      0x0c
#define I2C_STATUS_START    0x08
#define I2C_STATUS_RPTD_START    0x10
#define I2C_STATUS_ADDR_W_ACK    0x18
#define I2C_STATUS_DATA_WR_ACK    0x28
#define I2C_STATUS_ADDR_R_ACK    0x40
#define I2C_STATUS_DATA_RD_ACK    0x50
#define I2C_STATUS_DATA_RD_NOACK  0x58

#define I2C_BAUD_RATE_REG    0x0c
#define I2C_BAUD_RATE_PARAM(M,N)  ((((M) << 3) | ((N) & 0x7)) & 0x7f)
#define I2C_BAUD_RATE_RAW(C,M,N)  ((C)/((10*(M+1))<<(N+1)))
#define I2C_M_FROM_BAUD(baud)     (((baud) >> 3) & 0xf)
#define I2C_N_FROM_BAUD(baud)     ((baud) & 0x7)

#define I2C_SOFT_RESET    0x1c
#define I2C_TRANSFER_TIMEOUT 10000
#define I2C_READY_TIMEOUT 100

#define I2C_UNKNOWN        0x0
#define I2C_SLOW           0x1
#define I2C_FAST           0x2
#define I2C_FASTEST        0x3

/* rk i2c fifo max transfer bytes */
#define RK_I2C_FIFO_SIZE	32

/* rk i2c device register size */
#define RK_I2C_REGISTER_SIZE	3

/* i2c timerout */
#define I2C_TIMEOUT_US		100000  // 100000us = 100ms
#define I2C_RETRY_COUNT		3

#define I2C_ADAP_SEL_BIT(nr)	((nr) + 11)
#define I2C_ADAP_SEL_MASK(nr)	((nr) + 27)

#define RK_CEIL(x, y) \
	({ unsigned long __x = (x), __y = (y); (__x + __y - 1) / __y; })

/* Control register */
#define I2C_CON			0x000
#define I2C_CON_EN		(1 << 0)
#define I2C_CON_MOD(mod)	((mod) << 1)
#define I2C_MODE_TX		0x00
#define I2C_MODE_TRX		0x01
#define I2C_MODE_RX		0x02
#define I2C_MODE_RRX		0x03
#define I2C_CON_MASK		(3 << 1)

#define I2C_CON_START		(1 << 3)
#define I2C_CON_STOP		(1 << 4)
#define I2C_CON_LASTACK		(1 << 5)
#define I2C_CON_ACTACK		(1 << 6)

#define I2C_CON_SDA_CFG(cfg)	((cfg) << 8)
#define I2C_CON_STA_CFG(cfg)	((cfg) << 12)
#define I2C_CON_STO_CFG(cfg)	((cfg) << 14

#define I2C_CON_VERSION	        (0xff << 16)
#define I2C_CON_VERSION_SHIFT	16

/* Clock dividor register */
#define I2C_CLKDIV		0x004
#define I2C_CLK_DIV_HIGH_SHIFT	16
#define I2C_CLKDIV_VAL(divl, divh)	(((divl) & 0xffff) | (((divh) << 16) & 0xffff0000))

/* the slave address accessed  for master rx mode */
#define I2C_MRXADDR		0x008
#define I2C_MRXADDR_SET(vld, addr)	(((vld) << 24) | (addr))

/* the slave register address accessed  for master rx mode */
#define I2C_MRXRADDR		0x00c
#define I2C_MRXRADDR_SET(vld, raddr)	(((vld) << 24) | (raddr))

/* master tx count */
#define I2C_MTXCNT		0x010

/* master rx count */
#define I2C_MRXCNT		0x014

/* interrupt enable register */
#define I2C_IEN			0x018
#define I2C_BTFIEN		(1 << 0)
#define I2C_BRFIEN		(1 << 1)
#define I2C_MBTFIEN		(1 << 2)
#define I2C_MBRFIEN		(1 << 3)
#define I2C_STARTIEN		(1 << 4)
#define I2C_STOPIEN		(1 << 5)
#define I2C_NAKRCVIEN		(1 << 6)

/* interrupt pending register */
#define I2C_IPD                 0x01c
#define I2C_BTFIPD              (1 << 0)
#define I2C_BRFIPD              (1 << 1)
#define I2C_MBTFIPD             (1 << 2)
#define I2C_MBRFIPD             (1 << 3)
#define I2C_STARTIPD            (1 << 4)
#define I2C_STOPIPD             (1 << 5)
#define I2C_NAKRCVIPD           (1 << 6)
#define I2C_IPD_ALL_CLEAN       0x7f

/* finished count */
#define I2C_FCNT                0x020

/* I2C tx data register */
#define I2C_TXDATA_BASE         0X100

/* I2C rx data register */
#define I2C_RXDATA_BASE         0x200


#define I2C_GUID \
  { \
  0xadc1901b, 0xb83c, 0x4831, { 0x8f, 0x59, 0x70, 0x89, 0x8f, 0x26, 0x57, 0x1e } \
  }

#define I2C_MASTER_SIGNATURE          SIGNATURE_32 ('I', '2', 'C', 'M')

typedef struct {
  UINT32 Signature;
  EFI_HANDLE Controller;
  UINTN TclkFrequency;
  UINTN BaseAddress;
  INTN Bus;
  UINTN Config;
  BOOLEAN RuntimeSupport;
  EFI_I2C_MASTER_PROTOCOL I2cMaster;
  EFI_I2C_ENUMERATE_PROTOCOL I2cEnumerate;
  EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL I2cBusConf;
  ROCKCHIP_I2C_MASTER_PROTOCOL RockchipI2cMaster;
} I2C_MASTER_CONTEXT;

#define I2C_SC_FROM_MASTER(a) CR (a, I2C_MASTER_CONTEXT, I2cMaster, I2C_MASTER_SIGNATURE)
#define I2C_SC_FROM_ENUMERATE(a) CR (a, I2C_MASTER_CONTEXT, I2cEnumerate, I2C_MASTER_SIGNATURE)
#define I2C_SC_FROM_BUSCONF(a) CR (a, I2C_MASTER_CONTEXT, I2cBusConf, I2C_MASTER_SIGNATURE)

typedef struct {
  VENDOR_DEVICE_PATH Guid;
  UINTN Instance;
  EFI_DEVICE_PATH_PROTOCOL End;
} I2C_DEVICE_PATH;

typedef struct {
  UINT32 MinLowNs;
  UINT32 MinHighNs;
  UINT32 MaxRiseNs;
  UINT32 MaxFallNs;
} I2C_SPEC_VALUES;

typedef enum {
  RkI2cVersion0 = 0,
  RkI2cVersion1,
  RkI2cVersion5 = 5,
} I2C_VERSION;

STATIC
UINT32
I2cRead(
  IN I2C_MASTER_CONTEXT *I2cMasterContext,
  IN UINTN Off
  );

STATIC
EFI_STATUS
I2cWrite (
  IN I2C_MASTER_CONTEXT *I2cMasterContext,
  IN UINTN Off,
  IN UINT32 Val
  );

STATIC
CONST I2C_SPEC_VALUES *
I2cGetSpec (
  IN I2C_MASTER_CONTEXT *I2cMasterContext,
  IN UINT32 Speed);

EFI_STATUS
EFIAPI
I2cInitialise (
  IN EFI_HANDLE ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  );

STATIC
VOID
I2cCalBaudRate (
  IN I2C_MASTER_CONTEXT *I2cMasterContext,
  IN UINT32 Target,
  IN UINT32 ClkRate
  );

STATIC
EFI_STATUS
I2cAdapterBaudRate (
  IN I2C_MASTER_CONTEXT *I2cMasterContext,
  IN CONST UINT32 Target,
  IN CONST UINT32 ClkRate
  );

STATIC
EFI_STATUS
EFIAPI
I2cSetBusFrequency (
  IN CONST EFI_I2C_MASTER_PROTOCOL   *This,
  IN OUT UINTN                       *BusClockHertz
 );

EFI_STATUS
EFIAPI
I2cReset (
  IN CONST EFI_I2C_MASTER_PROTOCOL *This
  );

STATIC
VOID
I2cDisable (
  IN I2C_MASTER_CONTEXT *I2cMasterContext
  );

STATIC
EFI_STATUS
I2cStartEnable (
  IN I2C_MASTER_CONTEXT *I2cMasterContext,
  IN UINT32 Con,
  IN UINTN Timeout
  );

STATIC
EFI_STATUS
I2cStop (
  IN I2C_MASTER_CONTEXT *I2cMasterContext
  );

STATIC
EFI_STATUS
I2cReadOperation (
  IN I2C_MASTER_CONTEXT *I2cMasterContext,
  IN UINTN SlaveAddress,
  IN OUT UINT8 *buf,
  IN UINTN len,
  IN OUT UINTN *read,
  IN UINTN last,
  IN UINTN delay
  );

STATIC
EFI_STATUS
I2cWriteOperation (
  IN I2C_MASTER_CONTEXT *I2cMasterContext,
  IN UINTN SlaveAddress,
  IN OUT CONST UINT8 *buf,
  IN UINTN len,
  IN OUT UINTN *sent,
  IN UINTN timeout
  );

STATIC
EFI_STATUS
EFIAPI
I2cStartRequest (
  IN CONST EFI_I2C_MASTER_PROTOCOL *This,
  IN UINTN                         SlaveAddress,
  IN EFI_I2C_REQUEST_PACKET        *RequestPacket,
  IN EFI_EVENT                     Event      OPTIONAL,
  OUT EFI_STATUS                   *I2cStatus OPTIONAL
  );

STATIC
EFI_STATUS
EFIAPI
I2cEnumerate (
  IN CONST EFI_I2C_ENUMERATE_PROTOCOL *This,
  IN OUT CONST EFI_I2C_DEVICE         **Device
  );

STATIC
EFI_STATUS
EFIAPI
I2cEnableConf (
  IN CONST EFI_I2C_BUS_CONFIGURATION_MANAGEMENT_PROTOCOL *This,
  IN UINTN                                               I2cBusConfiguration,
  IN EFI_EVENT                                           Event      OPTIONAL,
  IN EFI_STATUS                                          *I2cStatus OPTIONAL
  );

STATIC
I2C_VERSION
I2cGetVersion(
  IN I2C_MASTER_CONTEXT *I2cMasterContext
  );

STATIC
VOID
I2cShowRegs (
  IN I2C_MASTER_CONTEXT *I2cMasterContex
  );

#endif // __RK_I2C_DXE_H__
