Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/i3c/master/mipi-i3c-hci/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 10 kB image not shown  

Quelle  cmd_v1.c   Sprache: C

 
// SPDX-License-Identifier: BSD-3-Clause
/*
 * Copyright (c) 2020, MIPI Alliance, Inc.
 *
 * Author: Nicolas Pitre <npitre@baylibre.com>
 *
 * I3C HCI v1.0/v1.1 Command Descriptor Handling
 */


#include <linux/bitfield.h>
#include <linux/i3c/master.h>

#include "hci.h"
#include "cmd.h"
#include "dat.h"
#include "dct.h"


/*
 * Address Assignment Command
 */


#define CMD_0_ATTR_A   FIELD_PREP(CMD_0_ATTR, 0x2)

#define CMD_A0_TOC       W0_BIT_(31)
#define CMD_A0_ROC       W0_BIT_(30)
#define CMD_A0_DEV_COUNT(v)  FIELD_PREP(W0_MASK(29, 26), v)
#define CMD_A0_DEV_INDEX(v)  FIELD_PREP(W0_MASK(20, 16), v)
#define CMD_A0_CMD(v)   FIELD_PREP(W0_MASK(14,  7), v)
#define CMD_A0_TID(v)   FIELD_PREP(W0_MASK( 6,  3), v)

/*
 * Immediate Data Transfer Command
 */


#define CMD_0_ATTR_I   FIELD_PREP(CMD_0_ATTR, 0x1)

#define CMD_I1_DATA_BYTE_4(v)  FIELD_PREP(W1_MASK(63, 56), v)
#define CMD_I1_DATA_BYTE_3(v)  FIELD_PREP(W1_MASK(55, 48), v)
#define CMD_I1_DATA_BYTE_2(v)  FIELD_PREP(W1_MASK(47, 40), v)
#define CMD_I1_DATA_BYTE_1(v)  FIELD_PREP(W1_MASK(39, 32), v)
#define CMD_I1_DEF_BYTE(v)  FIELD_PREP(W1_MASK(39, 32), v)
#define CMD_I0_TOC       W0_BIT_(31)
#define CMD_I0_ROC       W0_BIT_(30)
#define CMD_I0_RNW       W0_BIT_(29)
#define CMD_I0_MODE(v)   FIELD_PREP(W0_MASK(28, 26), v)
#define CMD_I0_DTT(v)   FIELD_PREP(W0_MASK(25, 23), v)
#define CMD_I0_DEV_INDEX(v)  FIELD_PREP(W0_MASK(20, 16), v)
#define CMD_I0_CP       W0_BIT_(15)
#define CMD_I0_CMD(v)   FIELD_PREP(W0_MASK(14,  7), v)
#define CMD_I0_TID(v)   FIELD_PREP(W0_MASK( 6,  3), v)

/*
 * Regular Data Transfer Command
 */


#define CMD_0_ATTR_R   FIELD_PREP(CMD_0_ATTR, 0x0)

#define CMD_R1_DATA_LENGTH(v)  FIELD_PREP(W1_MASK(63, 48), v)
#define CMD_R1_DEF_BYTE(v)  FIELD_PREP(W1_MASK(39, 32), v)
#define CMD_R0_TOC       W0_BIT_(31)
#define CMD_R0_ROC       W0_BIT_(30)
#define CMD_R0_RNW       W0_BIT_(29)
#define CMD_R0_MODE(v)   FIELD_PREP(W0_MASK(28, 26), v)
#define CMD_R0_DBP       W0_BIT_(25)
#define CMD_R0_DEV_INDEX(v)  FIELD_PREP(W0_MASK(20, 16), v)
#define CMD_R0_CP       W0_BIT_(15)
#define CMD_R0_CMD(v)   FIELD_PREP(W0_MASK(14,  7), v)
#define CMD_R0_TID(v)   FIELD_PREP(W0_MASK( 6,  3), v)

/*
 * Combo Transfer (Write + Write/Read) Command
 */


#define CMD_0_ATTR_C   FIELD_PREP(CMD_0_ATTR, 0x3)

#define CMD_C1_DATA_LENGTH(v)  FIELD_PREP(W1_MASK(63, 48), v)
#define CMD_C1_OFFSET(v)  FIELD_PREP(W1_MASK(47, 32), v)
#define CMD_C0_TOC       W0_BIT_(31)
#define CMD_C0_ROC       W0_BIT_(30)
#define CMD_C0_RNW       W0_BIT_(29)
#define CMD_C0_MODE(v)   FIELD_PREP(W0_MASK(28, 26), v)
#define CMD_C0_16_BIT_SUBOFFSET      W0_BIT_(25)
#define CMD_C0_FIRST_PHASE_MODE      W0_BIT_(24)
#define CMD_C0_DATA_LENGTH_POSITION(v) FIELD_PREP(W0_MASK(23, 22), v)
#define CMD_C0_DEV_INDEX(v)  FIELD_PREP(W0_MASK(20, 16), v)
#define CMD_C0_CP       W0_BIT_(15)
#define CMD_C0_CMD(v)   FIELD_PREP(W0_MASK(14,  7), v)
#define CMD_C0_TID(v)   FIELD_PREP(W0_MASK( 6,  3), v)

/*
 * Internal Control Command
 */


#define CMD_0_ATTR_M   FIELD_PREP(CMD_0_ATTR, 0x7)

#define CMD_M1_VENDOR_SPECIFIC      W1_MASK(63, 32)
#define CMD_M0_MIPI_RESERVED      W0_MASK(31, 12)
#define CMD_M0_MIPI_CMD       W0_MASK(11,  8)
#define CMD_M0_VENDOR_INFO_PRESENT     W0_BIT_( 7)
#define CMD_M0_TID(v)   FIELD_PREP(W0_MASK( 6,  3), v)


/* Data Transfer Speed and Mode */
enum hci_cmd_mode {
 MODE_I3C_SDR0  = 0x0,
 MODE_I3C_SDR1  = 0x1,
 MODE_I3C_SDR2  = 0x2,
 MODE_I3C_SDR3  = 0x3,
 MODE_I3C_SDR4  = 0x4,
 MODE_I3C_HDR_TSx = 0x5,
 MODE_I3C_HDR_DDR = 0x6,
 MODE_I3C_HDR_BT  = 0x7,
 MODE_I3C_Fm_FmP  = 0x8,
 MODE_I2C_Fm  = 0x0,
 MODE_I2C_FmP  = 0x1,
 MODE_I2C_UD1  = 0x2,
 MODE_I2C_UD2  = 0x3,
 MODE_I2C_UD3  = 0x4,
};

static enum hci_cmd_mode get_i3c_mode(struct i3c_hci *hci)
{
 struct i3c_bus *bus = i3c_master_get_bus(&hci->master);

 if (bus->scl_rate.i3c > 8000000)
  return MODE_I3C_SDR0;
 if (bus->scl_rate.i3c > 6000000)
  return MODE_I3C_SDR1;
 if (bus->scl_rate.i3c > 4000000)
  return MODE_I3C_SDR2;
 if (bus->scl_rate.i3c > 2000000)
  return MODE_I3C_SDR3;
 return MODE_I3C_SDR4;
}

static enum hci_cmd_mode get_i2c_mode(struct i3c_hci *hci)
{
 struct i3c_bus *bus = i3c_master_get_bus(&hci->master);

 if (bus->scl_rate.i2c >= 1000000)
  return MODE_I2C_FmP;
 return MODE_I2C_Fm;
}

static void fill_data_bytes(struct hci_xfer *xfer, u8 *data,
       unsigned int data_len)
{
 xfer->cmd_desc[1] = 0;
 switch (data_len) {
 case 4:
  xfer->cmd_desc[1] |= CMD_I1_DATA_BYTE_4(data[3]);
  fallthrough;
 case 3:
  xfer->cmd_desc[1] |= CMD_I1_DATA_BYTE_3(data[2]);
  fallthrough;
 case 2:
  xfer->cmd_desc[1] |= CMD_I1_DATA_BYTE_2(data[1]);
  fallthrough;
 case 1:
  xfer->cmd_desc[1] |= CMD_I1_DATA_BYTE_1(data[0]);
  fallthrough;
 case 0:
  break;
 }
 /* we consumed all the data with the cmd descriptor */
 xfer->data = NULL;
}

static int hci_cmd_v1_prep_ccc(struct i3c_hci *hci,
          struct hci_xfer *xfer,
          u8 ccc_addr, u8 ccc_cmd, bool raw)
{
 unsigned int dat_idx = 0;
 enum hci_cmd_mode mode = get_i3c_mode(hci);
 u8 *data = xfer->data;
 unsigned int data_len = xfer->data_len;
 bool rnw = xfer->rnw;
 int ret;

 /* this should never happen */
 if (WARN_ON(raw))
  return -EINVAL;

 if (ccc_addr != I3C_BROADCAST_ADDR) {
  ret = mipi_i3c_hci_dat_v1.get_index(hci, ccc_addr);
  if (ret < 0)
   return ret;
  dat_idx = ret;
 }

 xfer->cmd_tid = hci_get_tid();

 if (!rnw && data_len <= 4) {
  /* we use an Immediate Data Transfer Command */
  xfer->cmd_desc[0] =
   CMD_0_ATTR_I |
   CMD_I0_TID(xfer->cmd_tid) |
   CMD_I0_CMD(ccc_cmd) | CMD_I0_CP |
   CMD_I0_DEV_INDEX(dat_idx) |
   CMD_I0_DTT(data_len) |
   CMD_I0_MODE(mode);
  fill_data_bytes(xfer, data, data_len);
 } else {
  /* we use a Regular Data Transfer Command */
  xfer->cmd_desc[0] =
   CMD_0_ATTR_R |
   CMD_R0_TID(xfer->cmd_tid) |
   CMD_R0_CMD(ccc_cmd) | CMD_R0_CP |
   CMD_R0_DEV_INDEX(dat_idx) |
   CMD_R0_MODE(mode) |
   (rnw ? CMD_R0_RNW : 0);
  xfer->cmd_desc[1] =
   CMD_R1_DATA_LENGTH(data_len);
 }

 return 0;
}

static void hci_cmd_v1_prep_i3c_xfer(struct i3c_hci *hci,
         struct i3c_dev_desc *dev,
         struct hci_xfer *xfer)
{
 struct i3c_hci_dev_data *dev_data = i3c_dev_get_master_data(dev);
 unsigned int dat_idx = dev_data->dat_idx;
 enum hci_cmd_mode mode = get_i3c_mode(hci);
 u8 *data = xfer->data;
 unsigned int data_len = xfer->data_len;
 bool rnw = xfer->rnw;

 xfer->cmd_tid = hci_get_tid();

 if (!rnw && data_len <= 4) {
  /* we use an Immediate Data Transfer Command */
  xfer->cmd_desc[0] =
   CMD_0_ATTR_I |
   CMD_I0_TID(xfer->cmd_tid) |
   CMD_I0_DEV_INDEX(dat_idx) |
   CMD_I0_DTT(data_len) |
   CMD_I0_MODE(mode);
  fill_data_bytes(xfer, data, data_len);
 } else {
  /* we use a Regular Data Transfer Command */
  xfer->cmd_desc[0] =
   CMD_0_ATTR_R |
   CMD_R0_TID(xfer->cmd_tid) |
   CMD_R0_DEV_INDEX(dat_idx) |
   CMD_R0_MODE(mode) |
   (rnw ? CMD_R0_RNW : 0);
  xfer->cmd_desc[1] =
   CMD_R1_DATA_LENGTH(data_len);
 }
}

static void hci_cmd_v1_prep_i2c_xfer(struct i3c_hci *hci,
         struct i2c_dev_desc *dev,
         struct hci_xfer *xfer)
{
 struct i3c_hci_dev_data *dev_data = i2c_dev_get_master_data(dev);
 unsigned int dat_idx = dev_data->dat_idx;
 enum hci_cmd_mode mode = get_i2c_mode(hci);
 u8 *data = xfer->data;
 unsigned int data_len = xfer->data_len;
 bool rnw = xfer->rnw;

 xfer->cmd_tid = hci_get_tid();

 if (!rnw && data_len <= 4) {
  /* we use an Immediate Data Transfer Command */
  xfer->cmd_desc[0] =
   CMD_0_ATTR_I |
   CMD_I0_TID(xfer->cmd_tid) |
   CMD_I0_DEV_INDEX(dat_idx) |
   CMD_I0_DTT(data_len) |
   CMD_I0_MODE(mode);
  fill_data_bytes(xfer, data, data_len);
 } else {
  /* we use a Regular Data Transfer Command */
  xfer->cmd_desc[0] =
   CMD_0_ATTR_R |
   CMD_R0_TID(xfer->cmd_tid) |
   CMD_R0_DEV_INDEX(dat_idx) |
   CMD_R0_MODE(mode) |
   (rnw ? CMD_R0_RNW : 0);
  xfer->cmd_desc[1] =
   CMD_R1_DATA_LENGTH(data_len);
 }
}

static int hci_cmd_v1_daa(struct i3c_hci *hci)
{
 struct hci_xfer *xfer;
 int ret, dat_idx = -1;
 u8 next_addr = 0;
 u64 pid;
 unsigned int dcr, bcr;
 DECLARE_COMPLETION_ONSTACK(done);

 xfer = hci_alloc_xfer(1);
 if (!xfer)
  return -ENOMEM;

 /*
 * Simple for now: we allocate a temporary DAT entry, do a single
 * DAA, register the device which will allocate its own DAT entry
 * via the core callback, then free the temporary DAT entry.
 * Loop until there is no more devices to assign an address to.
 * Yes, there is room for improvements.
 */

 for (;;) {
  ret = mipi_i3c_hci_dat_v1.alloc_entry(hci);
  if (ret < 0)
   break;
  dat_idx = ret;
  ret = i3c_master_get_free_addr(&hci->master, next_addr);
  if (ret < 0)
   break;
  next_addr = ret;

  DBG("next_addr = 0x%02x, DAA using DAT %d", next_addr, dat_idx);
  mipi_i3c_hci_dat_v1.set_dynamic_addr(hci, dat_idx, next_addr);
  mipi_i3c_hci_dct_index_reset(hci);

  xfer->cmd_tid = hci_get_tid();
  xfer->cmd_desc[0] =
   CMD_0_ATTR_A |
   CMD_A0_TID(xfer->cmd_tid) |
   CMD_A0_CMD(I3C_CCC_ENTDAA) |
   CMD_A0_DEV_INDEX(dat_idx) |
   CMD_A0_DEV_COUNT(1) |
   CMD_A0_ROC | CMD_A0_TOC;
  xfer->cmd_desc[1] = 0;
  xfer->completion = &done;
  hci->io->queue_xfer(hci, xfer, 1);
  if (!wait_for_completion_timeout(&done, HZ) &&
      hci->io->dequeue_xfer(hci, xfer, 1)) {
   ret = -ETIME;
   break;
  }
  if ((RESP_STATUS(xfer->response) == RESP_ERR_ADDR_HEADER ||
       RESP_STATUS(xfer->response) == RESP_ERR_NACK) &&
      RESP_DATA_LENGTH(xfer->response) == 1) {
   ret = 0;  /* no more devices to be assigned */
   break;
  }
  if (RESP_STATUS(xfer->response) != RESP_SUCCESS) {
   ret = -EIO;
   break;
  }

  i3c_hci_dct_get_val(hci, 0, &pid, &dcr, &bcr);
  DBG("assigned address %#x to device PID=0x%llx DCR=%#x BCR=%#x",
      next_addr, pid, dcr, bcr);

  mipi_i3c_hci_dat_v1.free_entry(hci, dat_idx);
  dat_idx = -1;

  /*
 * TODO: Extend the subsystem layer to allow for registering
 * new device and provide BCR/DCR/PID at the same time.
 */

  ret = i3c_master_add_i3c_dev_locked(&hci->master, next_addr);
  if (ret)
   break;
 }

 if (dat_idx >= 0)
  mipi_i3c_hci_dat_v1.free_entry(hci, dat_idx);
 hci_free_xfer(xfer, 1);
 return ret;
}

const struct hci_cmd_ops mipi_i3c_hci_cmd_v1 = {
 .prep_ccc  = hci_cmd_v1_prep_ccc,
 .prep_i3c_xfer  = hci_cmd_v1_prep_i3c_xfer,
 .prep_i2c_xfer  = hci_cmd_v1_prep_i2c_xfer,
 .perform_daa  = hci_cmd_v1_daa,
};

Messung V0.5
C=96 H=99 G=97

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.