162306a36Sopenharmony_ci/* SPDX-License-Identifier: BSD-3-Clause */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2020, MIPI Alliance, Inc.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Nicolas Pitre <npitre@baylibre.com>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Common HCI stuff
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#ifndef HCI_H
1162306a36Sopenharmony_ci#define HCI_H
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/* Handy logging macro to save on line length */
1562306a36Sopenharmony_ci#define DBG(x, ...) pr_devel("%s: " x "\n", __func__, ##__VA_ARGS__)
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/* 32-bit word aware bit and mask macros */
1862306a36Sopenharmony_ci#define W0_MASK(h, l)  GENMASK((h) - 0,  (l) - 0)
1962306a36Sopenharmony_ci#define W1_MASK(h, l)  GENMASK((h) - 32, (l) - 32)
2062306a36Sopenharmony_ci#define W2_MASK(h, l)  GENMASK((h) - 64, (l) - 64)
2162306a36Sopenharmony_ci#define W3_MASK(h, l)  GENMASK((h) - 96, (l) - 96)
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/* Same for single bit macros (trailing _ to align with W*_MASK width) */
2462306a36Sopenharmony_ci#define W0_BIT_(x)  BIT((x) - 0)
2562306a36Sopenharmony_ci#define W1_BIT_(x)  BIT((x) - 32)
2662306a36Sopenharmony_ci#define W2_BIT_(x)  BIT((x) - 64)
2762306a36Sopenharmony_ci#define W3_BIT_(x)  BIT((x) - 96)
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistruct hci_cmd_ops;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* Our main structure */
3362306a36Sopenharmony_cistruct i3c_hci {
3462306a36Sopenharmony_ci	struct i3c_master_controller master;
3562306a36Sopenharmony_ci	void __iomem *base_regs;
3662306a36Sopenharmony_ci	void __iomem *DAT_regs;
3762306a36Sopenharmony_ci	void __iomem *DCT_regs;
3862306a36Sopenharmony_ci	void __iomem *RHS_regs;
3962306a36Sopenharmony_ci	void __iomem *PIO_regs;
4062306a36Sopenharmony_ci	void __iomem *EXTCAPS_regs;
4162306a36Sopenharmony_ci	void __iomem *AUTOCMD_regs;
4262306a36Sopenharmony_ci	void __iomem *DEBUG_regs;
4362306a36Sopenharmony_ci	const struct hci_io_ops *io;
4462306a36Sopenharmony_ci	void *io_data;
4562306a36Sopenharmony_ci	const struct hci_cmd_ops *cmd;
4662306a36Sopenharmony_ci	atomic_t next_cmd_tid;
4762306a36Sopenharmony_ci	u32 caps;
4862306a36Sopenharmony_ci	unsigned int quirks;
4962306a36Sopenharmony_ci	unsigned int DAT_entries;
5062306a36Sopenharmony_ci	unsigned int DAT_entry_size;
5162306a36Sopenharmony_ci	void *DAT_data;
5262306a36Sopenharmony_ci	unsigned int DCT_entries;
5362306a36Sopenharmony_ci	unsigned int DCT_entry_size;
5462306a36Sopenharmony_ci	u8 version_major;
5562306a36Sopenharmony_ci	u8 version_minor;
5662306a36Sopenharmony_ci	u8 revision;
5762306a36Sopenharmony_ci	u32 vendor_mipi_id;
5862306a36Sopenharmony_ci	u32 vendor_version_id;
5962306a36Sopenharmony_ci	u32 vendor_product_id;
6062306a36Sopenharmony_ci	void *vendor_data;
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/*
6562306a36Sopenharmony_ci * Structure to represent a master initiated transfer.
6662306a36Sopenharmony_ci * The rnw, data and data_len fields must be initialized before calling any
6762306a36Sopenharmony_ci * hci->cmd->*() method. The cmd method will initialize cmd_desc[] and
6862306a36Sopenharmony_ci * possibly modify (clear) the data field. Then xfer->cmd_desc[0] can
6962306a36Sopenharmony_ci * be augmented with CMD_0_ROC and/or CMD_0_TOC.
7062306a36Sopenharmony_ci * The completion field needs to be initialized before queueing with
7162306a36Sopenharmony_ci * hci->io->queue_xfer(), and requires CMD_0_ROC to be set.
7262306a36Sopenharmony_ci */
7362306a36Sopenharmony_cistruct hci_xfer {
7462306a36Sopenharmony_ci	u32 cmd_desc[4];
7562306a36Sopenharmony_ci	u32 response;
7662306a36Sopenharmony_ci	bool rnw;
7762306a36Sopenharmony_ci	void *data;
7862306a36Sopenharmony_ci	unsigned int data_len;
7962306a36Sopenharmony_ci	unsigned int cmd_tid;
8062306a36Sopenharmony_ci	struct completion *completion;
8162306a36Sopenharmony_ci	union {
8262306a36Sopenharmony_ci		struct {
8362306a36Sopenharmony_ci			/* PIO specific */
8462306a36Sopenharmony_ci			struct hci_xfer *next_xfer;
8562306a36Sopenharmony_ci			struct hci_xfer *next_data;
8662306a36Sopenharmony_ci			struct hci_xfer *next_resp;
8762306a36Sopenharmony_ci			unsigned int data_left;
8862306a36Sopenharmony_ci			u32 data_word_before_partial;
8962306a36Sopenharmony_ci		};
9062306a36Sopenharmony_ci		struct {
9162306a36Sopenharmony_ci			/* DMA specific */
9262306a36Sopenharmony_ci			dma_addr_t data_dma;
9362306a36Sopenharmony_ci			int ring_number;
9462306a36Sopenharmony_ci			int ring_entry;
9562306a36Sopenharmony_ci		};
9662306a36Sopenharmony_ci	};
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic inline struct hci_xfer *hci_alloc_xfer(unsigned int n)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	return kcalloc(n, sizeof(struct hci_xfer), GFP_KERNEL);
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic inline void hci_free_xfer(struct hci_xfer *xfer, unsigned int n)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	kfree(xfer);
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/* This abstracts PIO vs DMA operations */
11162306a36Sopenharmony_cistruct hci_io_ops {
11262306a36Sopenharmony_ci	bool (*irq_handler)(struct i3c_hci *hci, unsigned int mask);
11362306a36Sopenharmony_ci	int (*queue_xfer)(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
11462306a36Sopenharmony_ci	bool (*dequeue_xfer)(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
11562306a36Sopenharmony_ci	int (*request_ibi)(struct i3c_hci *hci, struct i3c_dev_desc *dev,
11662306a36Sopenharmony_ci			   const struct i3c_ibi_setup *req);
11762306a36Sopenharmony_ci	void (*free_ibi)(struct i3c_hci *hci, struct i3c_dev_desc *dev);
11862306a36Sopenharmony_ci	void (*recycle_ibi_slot)(struct i3c_hci *hci, struct i3c_dev_desc *dev,
11962306a36Sopenharmony_ci				struct i3c_ibi_slot *slot);
12062306a36Sopenharmony_ci	int (*init)(struct i3c_hci *hci);
12162306a36Sopenharmony_ci	void (*cleanup)(struct i3c_hci *hci);
12262306a36Sopenharmony_ci};
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ciextern const struct hci_io_ops mipi_i3c_hci_pio;
12562306a36Sopenharmony_ciextern const struct hci_io_ops mipi_i3c_hci_dma;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/* Our per device master private data */
12962306a36Sopenharmony_cistruct i3c_hci_dev_data {
13062306a36Sopenharmony_ci	int dat_idx;
13162306a36Sopenharmony_ci	void *ibi_data;
13262306a36Sopenharmony_ci};
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/* list of quirks */
13662306a36Sopenharmony_ci#define HCI_QUIRK_RAW_CCC	BIT(1)	/* CCC framing must be explicit */
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci/* global functions */
14062306a36Sopenharmony_civoid mipi_i3c_hci_resume(struct i3c_hci *hci);
14162306a36Sopenharmony_civoid mipi_i3c_hci_pio_reset(struct i3c_hci *hci);
14262306a36Sopenharmony_civoid mipi_i3c_hci_dct_index_reset(struct i3c_hci *hci);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci#endif
145