File Index
Files and directories
Sign in
FILE

dat_v1.c

File preview with syntax highlighting.

linux-6.19.14/drivers/i3c/master/mipi-i3c-hci/dat_v1.c C
  1// SPDX-License-Identifier: BSD-3-Clause
  2/*
  3 * Copyright (c) 2020, MIPI Alliance, Inc.
  4 *
  5 * Author: Nicolas Pitre <npitre@baylibre.com>
  6 */
  7
  8#include <linux/bitfield.h>
  9#include <linux/bitmap.h>
 10#include <linux/device.h>
 11#include <linux/errno.h>
 12#include <linux/i3c/master.h>
 13#include <linux/io.h>
 14
 15#include "hci.h"
 16#include "dat.h"
 17
 18
 19/*
 20 * Device Address Table Structure
 21 */
 22
 23#define DAT_1_AUTOCMD_HDR_CODE		W1_MASK(58, 51)
 24#define DAT_1_AUTOCMD_MODE		W1_MASK(50, 48)
 25#define DAT_1_AUTOCMD_VALUE		W1_MASK(47, 40)
 26#define DAT_1_AUTOCMD_MASK		W1_MASK(39, 32)
 27/*	DAT_0_I2C_DEVICE		W0_BIT_(31) */
 28#define DAT_0_DEV_NACK_RETRY_CNT	W0_MASK(30, 29)
 29#define DAT_0_RING_ID			W0_MASK(28, 26)
 30#define DAT_0_DYNADDR_PARITY		W0_BIT_(23)
 31#define DAT_0_DYNAMIC_ADDRESS		W0_MASK(22, 16)
 32#define DAT_0_TS			W0_BIT_(15)
 33#define DAT_0_MR_REJECT			W0_BIT_(14)
 34/*	DAT_0_SIR_REJECT		W0_BIT_(13) */
 35/*	DAT_0_IBI_PAYLOAD		W0_BIT_(12) */
 36#define DAT_0_STATIC_ADDRESS		W0_MASK(6, 0)
 37
 38#define dat_w0_read(i)		readl(hci->DAT_regs + (i) * 8)
 39#define dat_w1_read(i)		readl(hci->DAT_regs + (i) * 8 + 4)
 40#define dat_w0_write(i, v)	writel(v, hci->DAT_regs + (i) * 8)
 41#define dat_w1_write(i, v)	writel(v, hci->DAT_regs + (i) * 8 + 4)
 42
 43static int hci_dat_v1_init(struct i3c_hci *hci)
 44{
 45	unsigned int dat_idx;
 46
 47	if (!hci->DAT_regs) {
 48		dev_err(&hci->master.dev,
 49			"only DAT in register space is supported at the moment\n");
 50		return -EOPNOTSUPP;
 51	}
 52	if (hci->DAT_entry_size != 8) {
 53		dev_err(&hci->master.dev,
 54			"only 8-bytes DAT entries are supported at the moment\n");
 55		return -EOPNOTSUPP;
 56	}
 57
 58	if (!hci->DAT_data) {
 59		/* use a bitmap for faster free slot search */
 60		hci->DAT_data = bitmap_zalloc(hci->DAT_entries, GFP_KERNEL);
 61		if (!hci->DAT_data)
 62			return -ENOMEM;
 63
 64		/* clear them */
 65		for (dat_idx = 0; dat_idx < hci->DAT_entries; dat_idx++) {
 66			dat_w0_write(dat_idx, 0);
 67			dat_w1_write(dat_idx, 0);
 68		}
 69	}
 70
 71	return 0;
 72}
 73
 74static void hci_dat_v1_cleanup(struct i3c_hci *hci)
 75{
 76	bitmap_free(hci->DAT_data);
 77	hci->DAT_data = NULL;
 78}
 79
 80static int hci_dat_v1_alloc_entry(struct i3c_hci *hci)
 81{
 82	unsigned int dat_idx;
 83	int ret;
 84
 85	if (!hci->DAT_data) {
 86		ret = hci_dat_v1_init(hci);
 87		if (ret)
 88			return ret;
 89	}
 90	dat_idx = find_first_zero_bit(hci->DAT_data, hci->DAT_entries);
 91	if (dat_idx >= hci->DAT_entries)
 92		return -ENOENT;
 93	__set_bit(dat_idx, hci->DAT_data);
 94
 95	/* default flags */
 96	dat_w0_write(dat_idx, DAT_0_SIR_REJECT | DAT_0_MR_REJECT);
 97
 98	return dat_idx;
 99}
100
101static void hci_dat_v1_free_entry(struct i3c_hci *hci, unsigned int dat_idx)
102{
103	dat_w0_write(dat_idx, 0);
104	dat_w1_write(dat_idx, 0);
105	if (hci->DAT_data)
106		__clear_bit(dat_idx, hci->DAT_data);
107}
108
109static void hci_dat_v1_set_dynamic_addr(struct i3c_hci *hci,
110					unsigned int dat_idx, u8 address)
111{
112	u32 dat_w0;
113
114	dat_w0 = dat_w0_read(dat_idx);
115	dat_w0 &= ~(DAT_0_DYNAMIC_ADDRESS | DAT_0_DYNADDR_PARITY);
116	dat_w0 |= FIELD_PREP(DAT_0_DYNAMIC_ADDRESS, address) |
117		  (parity8(address) ? 0 : DAT_0_DYNADDR_PARITY);
118	dat_w0_write(dat_idx, dat_w0);
119}
120
121static void hci_dat_v1_set_static_addr(struct i3c_hci *hci,
122				       unsigned int dat_idx, u8 address)
123{
124	u32 dat_w0;
125
126	dat_w0 = dat_w0_read(dat_idx);
127	dat_w0 &= ~DAT_0_STATIC_ADDRESS;
128	dat_w0 |= FIELD_PREP(DAT_0_STATIC_ADDRESS, address);
129	dat_w0_write(dat_idx, dat_w0);
130}
131
132static void hci_dat_v1_set_flags(struct i3c_hci *hci, unsigned int dat_idx,
133				 u32 w0_flags, u32 w1_flags)
134{
135	u32 dat_w0, dat_w1;
136
137	dat_w0 = dat_w0_read(dat_idx);
138	dat_w1 = dat_w1_read(dat_idx);
139	dat_w0 |= w0_flags;
140	dat_w1 |= w1_flags;
141	dat_w0_write(dat_idx, dat_w0);
142	dat_w1_write(dat_idx, dat_w1);
143}
144
145static void hci_dat_v1_clear_flags(struct i3c_hci *hci, unsigned int dat_idx,
146				   u32 w0_flags, u32 w1_flags)
147{
148	u32 dat_w0, dat_w1;
149
150	dat_w0 = dat_w0_read(dat_idx);
151	dat_w1 = dat_w1_read(dat_idx);
152	dat_w0 &= ~w0_flags;
153	dat_w1 &= ~w1_flags;
154	dat_w0_write(dat_idx, dat_w0);
155	dat_w1_write(dat_idx, dat_w1);
156}
157
158static int hci_dat_v1_get_index(struct i3c_hci *hci, u8 dev_addr)
159{
160	unsigned int dat_idx;
161	u32 dat_w0;
162
163	for_each_set_bit(dat_idx, hci->DAT_data, hci->DAT_entries) {
164		dat_w0 = dat_w0_read(dat_idx);
165		if (FIELD_GET(DAT_0_DYNAMIC_ADDRESS, dat_w0) == dev_addr)
166			return dat_idx;
167	}
168
169	return -ENODEV;
170}
171
172const struct hci_dat_ops mipi_i3c_hci_dat_v1 = {
173	.init			= hci_dat_v1_init,
174	.cleanup		= hci_dat_v1_cleanup,
175	.alloc_entry		= hci_dat_v1_alloc_entry,
176	.free_entry		= hci_dat_v1_free_entry,
177	.set_dynamic_addr	= hci_dat_v1_set_dynamic_addr,
178	.set_static_addr	= hci_dat_v1_set_static_addr,
179	.set_flags		= hci_dat_v1_set_flags,
180	.clear_flags		= hci_dat_v1_clear_flags,
181	.get_index		= hci_dat_v1_get_index,
182};
~/ Read-only file preview.